When to use shared_ptr and when to use raw pointers?
c++, smart-pointers
Solution
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.
Problem
``` class B; class A { public: A () : m_b(new B()) { } shared_ptr<B> GimmeB () { return m_b; } private: shared_ptr<B> m_b; }; ``` Let's say B is a class that semantically should not exist outside of the lifetime of A, i.e., it makes absolutely no sense for B to exist by itself. Should `GimmeB` return a `shared_ptr<B>` or a `B*`? In general, is it good practice to completely avoid using raw pointers in C++ code, in lieu of smart pointers? I am of the opinion that `shared_ptr` should only be used when there is explicit transfer or sharing of ownership, which I think is quite rare outside of cases where a function allocates some memory, populates it with some data, and returns it, and there is understanding between the caller and the callee that the former is now "responsible" for that data.