4

我试图了解如何std::shared_ptr在 C++ 中使用。但这很令人困惑,我不明白如何创建指向同一个对象的多个共享指针。甚至文档和在线资料也不是很清楚。

以下是我编写的一小段代码,用于尝试理解std::shared_ptr的行为:

#include <iostream>
#include <memory>
using namespace std;

class Node
{
public:
    int key;
    Node()
    {
        key = 0;
    }
    Node(int k)
    {
        key = k;
    }
};

int main()
{
    Node node = Node(10);

    shared_ptr<Node> ptr1((shared_ptr<Node>)&node);
    cout << "Use Count: " << ptr1.use_count() << endl;

    // shared_ptr<Node> ptr2=make_shared<Node>(node);//This doesn't increase use_count
    shared_ptr<Node> ptr2((shared_ptr<Node>)&node);
    cout << "Use Count: " << ptr2.use_count() << endl;

    if (ptr1 == ptr2)
        cout << "ptr1 & ptr2 point to the same object!" << endl;

    if (ptr1.get() == ptr2.get())
        cout << "ptr1 & ptr2 point to the same address!" << endl;

    cout << "ptr1: " << ptr1 << "  "
         << "ptr2: " << ptr2 << endl;
    return 0;
}

根据我得到的输出,两者都ptr1指向ptr2同一个Node对象,但它们use_count都是 1。即使使用std::make_shared也不起作用,程序在退出前崩溃。

你能告诉我我做错了什么吗?以及如何创建shared_ptr指向同一个对象的多个(s)。

4

3 回答 3

7

shared_ptr当您单独创建 s (包括 using )时, use_count 不会增加make_shared,它们根本不共享。createdshared_ptr对其他 s 和被管理的指针一无所知shared_ptr,即使指针可能恰好是相同的(注意它可能导致多次破坏)。

你需要告诉哪些shared_ptrs 应该被共享;当您shared_ptr从另一个创建时,use_count 会增加shared_ptr。例如

shared_ptr<Node> ptr1 = make_shared<Node>(10);
cout<<"Use Count: "<<ptr1.use_count()<<endl; // 1

shared_ptr<Node> ptr2(ptr1);
cout<<"Use Count: "<<ptr2.use_count()<<endl; // 2
cout<<"Use Count: "<<ptr1.use_count()<<endl; // 2

顺便说一句:正如评论所暗示的那样,shared_ptr管理指向 的指针是危险的,该指针指向&node在堆栈上分配的对象。以下代码可能与您的意图非常匹配。

Node* node = new Node(10);

shared_ptr<Node> ptr1(node);
cout<<"Use Count: "<<ptr1.use_count()<<endl; // 1

shared_ptr<Node> ptr2(ptr1);
cout<<"Use Count: "<<ptr2.use_count()<<endl; // 2
cout<<"Use Count: "<<ptr1.use_count()<<endl; // 2
于 2018-01-12T06:33:00.953 回答
3

shared_ptr<>s own the object they are pointing too. That means you can't create a shared_ptr from a stack object. To create a shared_ptr use new or make_shared:

shared_ptr<Node> ptr1(new Node(42));
shared_ptr<Node> ptr2 = make_shared<Node>();
shared_ptr<Node> ptr3 = make_shared<Node>(99);

These are all separate objects and all have use_count()==1. If you want to copy them just do so:

shared_ptr<Node> copy1 = ptr1;

Now ptr1 and copy1 have use_count()==2.

于 2018-01-12T06:51:56.127 回答
2

there are multiple missunderstandings, but i will try to explain: in c++ objects are either stored on the stack or the heap. objects created on the stack will get destroyed and their memory gets released as soon as you leave the scope in which they are declared. this happens full automatically for you. for example:

int bla()
{
    int a = 1;
    int b = 2;
    int result = a+b;
    return result;
}

in this example the 3 intobjects will get created when the programm enter the function blaand will get destroyed when the function returns accordingly.

then you have the heap. you can create objects on the heap via new. this objects outlive the scope in which they got created, but you have to remember to destroy the objects via delete. because this is a common pitfall and source for memoryleaks the standard library provides helper classes (for example the shared_ptr which you already found) to overcome this issue. the idea is, that the shared_ptrobject will take the responsibility to delete the given object (which has to be on the heap(!) (yeah you can bypass this by a custom deleter, but thats a little bit more advanced than this explanation)) as soon as the shared_ptr itself gets destroyed. like the name suggests, the shared_ptr's intend is to be shared. to be shared you just copy the shared_ptr. the shared_ptr implementation has a custom copy constructor and copy assignment operator which will handle this by incrementing the use count and copying the address of the object that is currently handled. and this is the only way how a shared_ptr object will get to know wether there are other instances managing the same object or not. so to increase the use count you have to make a copy of the shared_ptr.

now let me explain what went wrong:

  1. your initial Node node = Node(10);is created on the stack (like the ints above). so there is no need to manage the lifetime manually. you created a shared_ptr, managing the address of this node. that is a misstake. as soon as you leave the scope the shared_ptr AND the node object itself(through the automatism on the stack) are going to delete the node object. and thats bad.

  2. lets imagine error 1 did not exists. so we have a second misstake: you are creating a second, seperate shared_ptr instead of copying from the first one. now both existing shared_ptr dont know about each other and each of them will try to delete the node object. so we have again a double delete.

lets pretend you want your Node object really be managed by a shared_ptr, you have to start with one shared_ptr and later copy from it as much as you want to share it. to create the first one you have 2 possiblilties:

std::shared_ptr<int> mysharedpointer (new int(ANYNUMBER));
auto mysharedpointer = std::make_shared<int>(ANYNUMBER);

usually you would prefer the second one, since it comes with a slight perfomance advantage and more safety when used in a function call context.

if you now want a second shared_ptr, sharing ownership with the first, you can do this by copying the first pointer:

auto mysecondsharedpointer = mysharedpointer;

and voila you have a copy associated with the shared ownership.

(this is all a bit simplified and i am sure i missed something. feel free to complete the answer)

于 2018-01-12T09:38:27.167 回答