考虑以下代码:
class A : public std::enable_shared_from_this<A>
{
public:
std::shared_ptr<A> f()
{
return shared_from_this();
}
};
int main()
{
A a;
std::shared_ptr<A> ptr = a.f();
}
此代码在Visual Studio 2017中终止。我想我在这里做错了。谁能帮我这个?我想在shared_from_this()创建一个shared_ptr。
答案 0 :(得分:7)
因为a
不是共享指针所拥有的。来自cppreference:
允许仅在先前共享的对象上调用shared_from_this,即在由std :: shared_ptr管理的对象上调用shared_from_this。否则行为是未定义的(直到C ++ 17)抛出std :: bad_weak_ptr(由默认构造的weak_this中的shared_ptr构造函数)(自C ++ 17开始)。
答案 1 :(得分:0)
无论您使用的C ++标准版本的具体规格是什么,您尝试做的事情都是不可能的。了解shared_from_this
规范的详细细节并不需要得出结论,代码包含设计矛盾:只是理解意图,即获得shared_ptr<A>
到{{} 1}},在一个名为this
的成员函数中,一个自动对象,足以确定设计是错误的。
事实上,任何尝试制作拥有智能指针(包括但不限于a
,unique_ptr
)指向(拥有)某个对象的对象&#34;作用域&#34;生命周期,这是一个对象,其生命周期由对象声明的范围定义,并以退出的东西结束:
是一个设计错误,因为:
shared_ptr
的任何变体new
(普通operator new
或nothrow
变体)创建; delete
或std::exit
来自main),无论如何(即使您拥有智能指针)已经照顾好了);试图摧毁已经破坏的物体是不行的。这包括构建一个智能指针,该指针拥有(即承诺return
)动态分配的类实例的成员:
delete
这里struct A {
int m;
};
#define OK 1
void f() {
A *p = new A;
#if OK
std::shared_ptr<A> own (p); // fine
#else
std::shared_ptr<int> own (&p->m); // bad
#endif
}
指向的对象的生命周期是动态管理的;通过程序代码明确确定的销毁时间,以及唯一成员p
的生命周期本质上与m
对象的生命周期相关联;但成员本身不需要明确破坏,不得删除。如果A
预处理器常量为1,则一切都很好;如果它为0,则表示您正在尝试明确管理成员的生命周期,这是不合理的。
关于术语&#34;明确&#34;致电OK
:虽然delete
运算符从未出现在代码中,但其调用隐含在使用delete
;换句话说,std::shared_ptr
明确使用std::shared_ptr
,因此使用delete
(或其他类似的拥有智能指针)是间接使用std::shared_ptr
。
分享delete
所有权的唯一安全方法是直接或间接地从另一个shared_ptr
创建一个。这是{{1}的基本属性指向一个对象的所有实例必须可追溯到一个用原始指针构建的实例(或者用shared_ptr
)。
这是由于所有权信息(通常是引用计数,但如果您喜欢低效的实现,可能是链接列表)直接导致托管对象内的不,但在由shared_ptr
创建的信息块。这不仅仅是make_shared
的属性,它是所有这些外部管理对象的生命现实,没有全局注册表,找不到管理员是不可能的。
这些智能指针的基本设计决策是无需修改托管对象即可使用智能指针;因此它们可用于现有数据类型(包括基本类型)。
shared_ptr
的基本属性会产生一个问题:因为每一层代码(可能需要调用需要拥有指针的函数)都需要保留std::shared_ptr
的副本,这可以创建一个拥有智能指针的Web,其中一些可能驻留在一个对象中,该对象的生命周期由另一个由该精确智能指针管理的生命周期管理;因为智能指针基本规范是在破坏负责破坏的智能指针的所有副本之前不破坏托管对象,所以这些对象永远不会被销毁(如指定的那样;这是不是 a参考计数的特定实施选择的结果)。有时需要一个不具备影响托管对象生命周期的硬币的拥有智能指针的副本,因此需要弱智能指针。
一个(非空)弱智能指针总是直接或间接地拥有一个拥有智能指针的副本,直接或间接地复制获得所有权的原始智能指针。那个&#34;弱参考&#34;实际上是一个强大的&#34;拥有智能指针指向有关智能指针的其他拥有副本的存在的信息:只要存在弱智能指针,就可以确定是否存在实时拥有智能指针,如果是,则获取副本,这是一个共享的智能指针,它是原始的精确副本(原始的生命周期可能已经结束了许多代的复制之前)。
弱智能指针的唯一目的是获取原始的副本。
shared_ptr
shared_ptr
的唯一用途是获取原始 std::enable_shared_from_this
的副本;这意味着这种拥有智能指针必须已经存在。没有新原件(另一个智能指针取得所有权)。
仅针对仅由std::enable_shared_from_this
管理的课程使用shared_ptr
。
std::enable_shared_from_this
关于理论原则所说的一切,有助于理解shared_ptr
包含什么,如果正确使用它会如何产生std::enable_shared_from_this
(以及为什么它不能被认为有效)在任何其他情况下)。
&#34;魔法&#34; std::enable_shared_from_this
的{{1}}可能看起来很神秘,太神奇了以至于用户不必考虑它,但它实际上非常简单:它保留shared_ptr
打算成为副本原始。显然它不能构造为这样的副本,因为原始的甚至在构造std::enable_shared_from_this
子对象时甚至无法初始化:有效的拥有智能指针只能引用完全构造的对象,因为它拥有它并负责销毁它。 [即使有人作弊,在管理对象完全构建之前制作一个拥有的智能指针,因此可以破坏,拥有的智能指针会有过早破坏的风险(即使在正常的事件过程中它的寿命很长,它例如,可以缩短例外情况。]
因此,weak_ptr
中的数据成员初始化本质上是默认初始化:&#34;弱指针&#34;那时为空。
只有当原始最终获得托管对象的所有权时,它才能与std::enable_shared_from_this
串联:构建原始 std::enable_shared_from_this
将在std::enable_shared_from_this
内设置一次shared_ptr
成员。这些组件之间的主动勾结是使这些组件有效的唯一方法。
用户有责任仅在可能会返回原始的副本时调用weak_ptr
,即之后原来的已经构建完毕。
虚假的拥有智能指针是一种不进行清理的指针:仅在名称中拥有智能指针。他们是&#34;拥有&#34;的特例。以这种方式使用的智能指针,不执行破坏或清理。这表面上意味着它们可以用于生命周期(足够长)并且需要假装拥有智能指针的对象;与真正拥有的智能指针不同,保留副本不会延长对象的生命周期,因此生命周期应该更长。 (因为拥有智能指针的副本可以存储在全局变量中,所以在std::enable_shared_from_this
shared_from_this
之后,该对象仍然可能存在。)
这些非拥有者显然是一个矛盾的术语,很少安全(但在少数情况下可以证明是安全的)。
他们很少解决一个合法的问题(一个不是设计非常糟糕的直接后果):接口中的return
意味着接收者期望能够延长其生命周期托管对象。