智能指针所有权语义和平等

时间:2016-12-14 12:59:45

标签: c++ smart-pointers ownership-semantics

我有几个关于智能指针的问题,早些时候我并没有给予任何信任。

  1. 拥有一个对象,指向一个对象以及管理一个智能指针世界中的对象意味着什么?之前我认为拥有该对象的人也指向它并管理该对象。现在,我知道智能指针可以拥有一个对象,但指向另一个对象(别名构造函数)。在这里,我找到了一个非常好的解释,拥有一个对象意味着什么 - > http://www.umich.edu/~eecs381/handouts/C++11_smart_ptrs.pdf,但我仍然无法区分这三个词。
  2. 如果指针拥有一个对象,但指向另一个对象,他管理的是哪个对象?他拥有的那个,或者他所指的那个,还是两个?拥有一个对象的重点是什么,但没有指向它?
  3. 两个智能指针何时相等?两个指针可以拥有相同的对象并且在同一时间不同吗?我对他们的价值平等并不感兴趣,而是对所有权感兴趣。
  4. 为什么所有权订单很重要(除了将指针用作容器中的键)?我想这只适用于shared_ptr。
  5. 一切都始于试图了解owner_before,现在我比开始探索这个话题时更加困惑.. :(

3 个答案:

答案 0 :(得分:1)

我认为你所有的困惑都来自"别名构造函数":

template <typename U>
shared_ptr(const shared_ptr<U>& x, element_type* p)

这件东西的用途是什么?嗯,它很少使用,但它的作用是&#34;分享&#34;某个对象x的所有权,但是当您取消引用它时,您将获得p。这就是全部。它绝不会删除p或对其执行任何其他操作。

如果你有这样的东西可能会有用:

struct Foo {
    Bar bar;
};

struct Baz {
    Baz(shared_ptr<Bar> bar) : m_bar(bar) {}
    shared_ptr<Bar> m_bar;
};

int main()
{
    auto foo = make_shared<Foo>();
    Baz baz(shared_ptr<Bar>(foo, &foo.bar));
}

现在baz可以管理foo的生命周期而不知道它正在做什么 - 它只关心它管理{{1}的生命周期},但由于我们的Bar属于bar,我们无法销毁foo而不会销毁foo,因此我们使用别名构造函数。

但实际上,我们不这样做,因为这个用例非常罕见。

答案 1 :(得分:0)

Old&#34; raw&#34;指针:

someType* pR = new someType(param1, param2); //pR is a pointer
MyOwner.TakeOwnershipOf(pR); // Now MyOwner is the owner, **the one who ONLY should call 'delete pR;'**

智能指针:

std::shared_ptr<someType> sp = std::make_shared<someType>(param1, param2);

&#34; SP&#34; 现在是所有者(代码中没有&#34; pR&#34;但内部却是)。而且您不需要拨打电话&#34;删除pR&#34;。它是一个内部存储指向pR的指针的对象,当不再需要它时将其删除。

sp是一个对象。 &#34;&SP- GT;任何&#34;就像&#34; pR-&gt;任何&#34;。这可能会让你觉得sp也是一个指针。不,它发生在&#34; - &gt;&#34;超载了。

更多重载:

sp.get()pR相同。 *sp*pR相同

sp1 == sp2pR1 == pR2相同,与sp1.get()==sp2.get()相同

关于shared_ptr的好处是,例如,当您需要将相同的指针存储在多个容器中时。如果删除了某个容器,则还应删除存储的指针(sp,谁拥有pR)。这将使存储在其他容器中的指针无效。 shared_ptr不负责检查有关此指针存在的其他容器,而是负责它。也就是说,您可以安全地删除sp,因为pR只会被存储sp的最后一个容器删除。

答案 2 :(得分:0)

所有权

您的困惑是因为所有权不是编译器可以验证的内容;作为一名程序员,你需要推断出它。

如果p的存在保证q的存在(最好没有内存泄漏),我们可以说任何对象p 拥有 q
简单的情况是直接所有权,解除分配p也会解除分配q,例如如果qp的成员,或qdelete的析构函数中与p明确取消分配。
智能指针使人们明白这一点。如果q存储在std::unique_ptr的{​​{1}}成员中,则我们知道p拥有p。您不需要搜索(可能缺失或重复)删除语句。

所有权也具有传递性,如果q拥有pq拥有q,则r必须拥有p

混叠

如果r直接拥有p,并且我们想要创建拥有q的{​​{1}},那么它还必须拥有shared_ptr。否则,如果q被销毁,那么p也是如此,尽管我们的共享指针存在。

这就是std :: shared_ptr的别名构造函数(在John的回答中代表)。

通过延长p的生命周期来延长q的生命周期,因此我们指向实际拥有q的{​​{1}}。我们向编译器断言p实际上拥有q,因此共享ptr传递地拥有p

如果p不拥有q,那么您的程序将会编译,但它会被破坏,就像您手动拨打q两次一样。

比较

对于stl智能指针,比较将传递给原始指针。因此,如果智能指针取消引用相同的对象,则它们是相等的,并且比较是关于内存位置的。没有任何已定义的行为指定内存位置,因此除了存储在pq之外,您无法使用它。