Should I use std::shared pointer to pass a pointer?

前端 未结 5 767
醉话见心
醉话见心 2021-02-04 02:18

Suppose I have an object which is managed by an std::unique_ptr. Other parts of my code need to access this object. What is the right solution to pass the pointer?

5条回答
  •  逝去的感伤
    2021-02-04 02:42

    If the ownership of the managed object is not being transferred (and because it's a unique_ptr, ownership cannot be shared) then it's more correct to separate the logic in the called function from the concept of ownership. We do this by calling by reference.

    This is a convoluted way of saying:

    Given:

    std::unique_ptr thing_ptr;
    

    to change the Thing:

    // declaration
    void doSomethingWith(Thing& thing); 
    
    // called like this
    doSomethingWith(*thing_ptr);
    

    to use the Thing without modifying it.

    // declaration
    void doSomethingWith(const Thing& thing); 
    
    // called like this
    doSomethingWith(*thing_ptr);
    

    The only time you'd want to mention the unique_ptr in the function signature would be if you were transferring ownership:

    // declaration
    void takeMyThing(std::unique_ptr p);
    
    // call site
    takeMyThing(std::move(thing_ptr));
    

    You never need to do this:

    void useMyThing(const std::unique_ptr& p);
    

    The reason that this would be a bad idea is that if confuses the logic of useMyThing with the concept of ownership, thus narrowing the scope for re-use.

    Consider:

    useMyThing(const Thing& thing);
    
    Thing x;
    std::unique_ptr thing_ptr = makeAThing();
    useMyThing(x);
    useMyThing(*thing_ptr);
    

    Update:

    Noting the update to the question - storing (non-owning) references to this object.

    One way to do this is indeed to store a pointer. However, pointers suffer from the possibility of a logic error in that they can legally be null. Another problem with pointers is that they do not play nicely with std:: algorithms and containers - requiring custom compare functions and the like.

    There is a std::-compliant way to do this - the std::reference_wrapper<>

    So rather than this:

    std::vector my_thing_ptrs;
    

    do this:

    std::vector> my_thing_refs;
    

    Since std::reference_wrapper defines an operator T&, you can use the reference_wrapped object in any expression that would expect a T.

    for example:

    std::unique_ptr t1 = make_thing();
    std::unique_ptr t2 = make_thing();
    std::unique_ptr t3 = make_thing();
    
    std::vector> thing_cache;
    
    store_thing(*t1);
    store_thing(*t2);
    store_thing(*t3);
    
    int total = 0;
    for(const auto& t : thing_cache) {
      total += value_of_thing(t);
    }
    

    where:

    void store_thing(const Thing& t) {
      thing_cache.push_back(std::cref(t));
    }
    
    int value_of_thing(const Thing& t) {
      return ;
    }
    

提交回复
热议问题