shared_ptrs 被删除两次

Jab*_*cky 7 c++ vector shared-ptr stdvector c++11

我想将指向Object类的共享指针存储在向量中:

测试代码:

#include <vector>
#include <iostream>
#include <memory>

using namespace std;   // only for brevity

class Object
{
public:
  int n;
  Object(int n) : n(n) { cout << "Object("  << n <<")\n"; }
  ~Object() { cout << "~Object(" << n << "))\n"; n = 0xdddddddd; }

};

void Test()
{
  std::shared_ptr<Object> p1(make_shared<Object>(Object(123)));
  std::vector<shared_ptr<Object>> v;

  cout << "before push_back\n";
  v.push_back(std::make_shared<Object>(Object(2)));
  v.push_back(p1);
  cout << "after push_back\n";

  cout << "Vector content:\n";
  for (auto& p : v)
    cout << "  " << p->n << "\n"; ;
}

int main()
{
  Test();
  cout << "after Test()\n";
}
Run Code Online (Sandbox Code Playgroud)

输出是

Object(123)
~Object(123))        <<< why is the destructor called here?
before push_back
Object(2)
~Object(2))          <<< why is the destructor called here?
after push_back
Vector content:
  2
  123
~Object(2))          <<< destructor called again 
~Object(123))
after Test()
Run Code Online (Sandbox Code Playgroud)

我不明白为什么析构函数被调用两次。

OTOH 矢量内容正是我想要的。

Nut*_*ker 14

我不明白为什么析构函数被调用两次。

因为在这里创建了不必要的临时对象:

std::shared_ptr<Object> p1(make_shared<Object>(Object(123)));
                                               ^^^
                                               temporary object
Run Code Online (Sandbox Code Playgroud)

和这里:

v.push_back(std::make_shared<Object>(Object(2)));
                                     ^^^
                                     temporary object
Run Code Online (Sandbox Code Playgroud)

它应该是

std::shared_ptr<Object> p1(make_shared<Object>(123));
Run Code Online (Sandbox Code Playgroud)

v.push_back(std::make_shared<Object>(2));
Run Code Online (Sandbox Code Playgroud)

为什么?

因为std::make_shared构造了一个类型为 T 的对象,并使用 args 作为 T 的构造函数的参数列表将其包装在 std::shared_ptr 中。在您的代码中,您正在创建一个立即被销毁的额外对象,从而调用析构函数。

为什么你没有看到Object(int n);构造函数被临时对象调用?

Object(int n);确实为临时对象调用了构造函数,但是由于 持有的对象std::shared_ptr是通过复制构造函数创建的(因此,通过复制临时对象),您不会看到Object(int n);对它的调用,而是对Object(Object const& other);.

演示中,您可以看到首先Object(int n);为临时对象调用构造函数,然后Object(Object const& other);std::shared_ptr.

  • @Jabberwocky,你*确实*看到了临时建筑的构造。您看不到的是共享对象的复制构造。 (2认同)

Gui*_*cot 5

这是因为您必须销毁临时值。

std::make_shared函数接受任意数量的参数并用它构造给定类型的值。

您构造 aObject并将其传递给std::make_shared,后者又使用 构造一个值new。然后,临时对象被销毁。之后,共享指针也被销毁。

只需在您的代码中更改它:

std::shared_ptr<Object> p1(make_shared<Object>(123));

// ...  

v.push_back(std::make_shared<Object>(2));
Run Code Online (Sandbox Code Playgroud)

并且对于每个值,您只会看到一个析构函数。