When to use shared_ptr and when to use raw pointers?

后端 未结 10 1344
情歌与酒
情歌与酒 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:06

    It is good practice to avoid using raw pointers, but you can not just replace everything with shared_ptr. In the example, users of your class will assume that it's ok to extend B's lifetime beyond that of A's, and may decide to hold the returned B object for some time for their own reasons. You should return a weak_ptr, or, if B absolutely cannot exist when A is destroyed, a reference to B or simply a raw pointer.

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

    If you don't want the callee of GimmeB() to be able to extend the lifetime of the pointer by keeping a copy of the ptr after the instance of A dies, then you definitely should not return a shared_ptr.

    If the callee is not supposed to keep the returned pointer for long periods of time, i.e. there's no risk of the instance of A's lifetime expiring before the pointer's, then raw pointer would be better. But even a better choice is simply to use a reference, unless there's a good reason to use an actual raw pointer.

    And finally in the case that the returned pointer can exist after the lifetime of the A instance has expired, but you don't want the pointer itself extend the lifetime of the B, then you can return a weak_ptr, which you can use to test whether it still exists.

    The bottom line is that there's usually a nicer solution than using a raw pointer.

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

    The following is a good rule of thumb:

    • When there is no transfer of or shared ownership references or plain pointers are good enough. (Plain pointers are more flexible than references.)
    • When there is transfer of ownership but no shared ownership then std::unique_ptr<> is a good choice. Often the case with factory functions.
    • When there is shared ownership, then it is a good use case for std::shared_ptr<> or boost::intrusive_ptr<>.

    It is best to avoid shared ownership, partly because they are most expensive in terms of copying and std::shared_ptr<> takes double of the storage of a plain pointer, but, most importantly, because they are conducive for poor designs where there are no clear owners, which, in turn, leads to a hairball of objects that cannot destroy because they hold shared pointers to each other.

    The best design is where clear ownership is established and is hierarchical, so that, ideally, no smart pointers are required at all. For example, if there is a factory that creates unique objects or returns existing ones, it makes sense for the factory to own the objects it creates and just keep them by value in an associative container (such as std::unordered_map), so that it can return plain pointers or references to its users. This factory must have lifetime that starts before its first user and ends after its last user (the hierarchical property), so that users cannot possible have a pointer to an already destroyed object.

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

    Generally, I would avoid using raw pointers as far as possible since they have very ambiguous meaning - you might have to deallocate the pointee, but maybe not, and only human-read and -written documentation tells you what the case is. And documentation is always bad, outdated or misunderstood.

    If ownership is an issue, use a smart pointer. If not, I'd use a reference if practicable.

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

    When you say: "Let's say B is a class that semantically should not exist outside of the lifetime of A"

    This tells me B should logically not exist without A, but what about physically existing? If you can be sure no one will try using a *B after A dtors than perhaps a raw pointer will be fine. Otherwise a smarter pointer may be appropriate.

    When clients have a direct pointer to A you have to trust they'll handle it appropriately; not try dtoring it etc.

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

    The question "when should I use shared_ptr and when should I use raw pointers?" has a very simple answer:

    • Use raw pointers when you do not want to have any ownership attached to the pointer. This job can also often be done with references. Raw pointers can also be used in some low level code (such as for implementing smart pointers, or implementing containers).
    • Use unique_ptr or scope_ptr when you want unique ownership of the object. This is the most useful option, and should be used in most cases. Unique ownership can also be expressed by simply creating an object directly, rather than using a pointer (this is even better than using a unique_ptr, if it can be done).
    • Use shared_ptr or intrusive_ptr when you want shared ownership of the pointer. This can be confusing and inefficient, and is often not a good option. Shared ownership can be useful in some complex designs, but should be avoided in general, because it leads to code which is hard to understand.

    shared_ptrs perform a totally different task from raw pointers, and neither shared_ptrs nor raw pointers are the best option for the majority of code.

    0 讨论(0)
提交回复
热议问题