When to use shared_ptr and when to use raw pointers?

后端 未结 10 1345
情歌与酒
情歌与酒 2020-11-29 16:27
class B;

class A
{
public:
    A ()
        : m_b(new B())
    {
    }

    shared_ptr GimmeB ()
    {
        return m_b;
    }

private:
    shared_ptr&l         


        
相关标签:
10条回答
  • 2020-11-29 17:23
    1. You allocate B at constuction of A.
    2. You say B shouldn't persist outside As lifetime.
      Both these point to B being a member of A and a just returning a reference accessor. Are you overengineering this?
    0 讨论(0)
  • 2020-11-29 17:25

    I agree with your opinion that shared_ptr is best used when explicit sharing of resources occurs, however there are other types of smart pointers available.

    In your precise case: why not return a reference ?

    A pointer suggests that the data might be null, however here there will always be a B in your A, thus it will never be null. The reference asserts this behavior.

    That being said, I have seen people advocating the use of shared_ptr even in non-shared environments, and giving weak_ptr handles, with the idea of "securing" the application and avoiding stale pointers. Unfortunately, since you can recover a shared_ptr from the weak_ptr (and it is the only way to actually manipulate the data), this is still shared ownership even if it was not meant to be.

    Note: there is a subtle bug with shared_ptr, a copy of A will share the same B as the original by default, unless you explicitly write a copy constructor and a copy assignment operator. And of course you would not use a raw pointer in A to hold a B, would you :) ?


    Of course, another question is whether you actually need to do so. One of the tenets of good design is encapsulation. To achieve encapsulation:

    You shall not return handles to your internals (see Law of Demeter).

    so perhaps the real answer to your question is that instead of giving away a reference or pointer to B, it should only be modified through A's interface.

    0 讨论(0)
  • 2020-11-29 17:25

    I found that the C++ Core Guidelines give some very useful hints for this question:

    To use raw pointer(T*) or smarter pointer depends on who owns the object (whose responsibility to release memory of the obj).

    own :

    smart pointer, owner<T*>
    

    not own:

    T*, T&, span<>
    

    owner<>, span<> is defined in Microsoft GSL library

    here is the rules of thumb:

    1) never use raw pointer(or not own types) to pass ownership

    2) smart pointer should only be used when ownership semantics are intended

    3) T* or owner designate a individual object(only)

    4) use vector/array/span for array

    5) To my undetstanding, shared_ptr is usually used when you don't know who will release the obj, for example, one obj is used by multi-thread

    0 讨论(0)
  • 2020-11-29 17:27

    Your analysis is quite correct, I think. In this situation, I also would return a bare B*, or even a [const] B& if the object is guaranteed to never be null.

    Having had some time to peruse smart pointers, I arrived at some guidelines which tell me what to do in many cases:

    • If you return an object whose lifetime is to be managed by the caller, return std::unique_ptr. The caller can assign it to a std::shared_ptr if it wants.
    • Returning std::shared_ptr is actually quite rare, and when it makes sense, it is generally obvious: you indicate to the caller that it will prolong the lifetime of the pointed-to object beyond the lifetime of the object which was originally maintaining the resource. Returning shared pointers from factories is no exception: you must do this eg. when you use std::enable_shared_from_this.
    • You very rarely need std::weak_ptr, except when you want to make sense of the lock method. This has some uses, but they are rare. In your example, if the lifetime of the A object was not deterministic from the caller's point of view, this would have been something to consider.
    • If you return a reference to an existing object whose lifetime the caller cannot control, then return a bare pointer or a reference. By doing so, you tell the caller that an object exists and that she doesn't have to take care of its lifetime. You should return a reference if you don't make use of the nullptr value.
    0 讨论(0)
提交回复
热议问题