我有几个关于智能指针的问题,早些时候我并没有给予任何信任。
一切都始于试图了解owner_before,现在我比开始探索这个话题时更加困惑.. :(
答案 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 == sp2
与pR1 == pR2
相同,与sp1.get()==sp2.get()
相同
关于shared_ptr的好处是,例如,当您需要将相同的指针存储在多个容器中时。如果删除了某个容器,则还应删除存储的指针(sp,谁拥有pR)。这将使存储在其他容器中的指针无效。 shared_ptr不负责检查有关此指针存在的其他容器,而是负责它。也就是说,您可以安全地删除sp
,因为pR
只会被存储sp
的最后一个容器删除。
答案 2 :(得分:0)
您的困惑是因为所有权不是编译器可以验证的内容;作为一名程序员,你需要推断出它。
如果p
的存在保证q
的存在(最好没有内存泄漏),我们可以说任何对象p
拥有 q
。
简单的情况是直接所有权,解除分配p
也会解除分配q
,例如如果q
是p
的成员,或q
在delete
的析构函数中与p
明确取消分配。
智能指针使人们明白这一点。如果q
存储在std::unique_ptr
的{{1}}成员中,则我们知道p
拥有p
。您不需要搜索(可能缺失或重复)删除语句。
所有权也具有传递性,如果q
拥有p
且q
拥有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智能指针,比较将传递给原始指针。因此,如果智能指针取消引用相同的对象,则它们是相等的,并且比较是关于内存位置的。没有任何已定义的行为指定内存位置,因此除了存储在p
或q
之外,您无法使用它。