我在MS Visual Studio 10中运行此代码,
#include <iostream>
#include <memory>
using namespace std;
class A
{
int i;
public:
A(int j) : i(j) {}
~A() {}
void fun()
{
cout << "A::i = " << i << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A aObj(12);
std::shared_ptr<A> const pObj (&aObj,
[] (A* pA) {
cout << "lambda deleter" << endl;
});
aObj.~A();
pObj->fun();
return 0;
}
这会打印/保存已删除的对象的数据成员,而不会报告任何类型的错误。
请写信:
shared_ptr
pObj没有报告(在运行时)底层对象已被删除?weak_ptr
可以在类似情况下提供帮助。 weak_ptr
与语义一起使用,即对象引用的生命周期超过它引用的对象。答案 0 :(得分:20)
为什么shared_ptr pObj不报告(在运行时)底层对象已被删除?
因为shared_ptr
不是魔术 1 。只有当删除该对象时,它才知道何时删除了包含的对象。当您使用shared_ptr
时,您已与shared_ptr
签订了合同。该合同的其中一个租户(实际上,你用任何类型的智能指针输入的任何合同)是你不能删除指针。 shared_ptr
实例拥有指针, it 将删除它,而不是你。
违反该合同会导致未定义的行为。
由于我正在创建一个const shared_ptr,意味着不能使用它来引用任何其他对象,为什么在删除对象时不调用lambda。
同样,shared_ptr
只能知道当它删除所包含的对象时才会删除它。如果你违反合同,它对对象的状态一无所知。
weak_ptr可以在类似的情况下有所帮助。 weak_ptr与语义一起使用,即对象引用的生命周期超过它引用的对象。
weak_ptr
不再是shared_ptr
的神奇赋予。 weak_ptr
只知道创建它的shared_ptr
集合知道什么。如果shared_ptr
不知道该对象已被删除,则weak_ptr
也不会。
1 通过“魔术”,我的意思是做一些在C ++中无法做到的事情。如果你想知道一个函数被调用(析构函数是一个函数调用),那么只有两种方法可以做到。该函数告诉你它已被调用(通过设置你可以看到的值),或者你设置一个系统,人们调用你的函数,然后调用另一个函数。
第一个系统需要一个明确写入的函数,让人们知道它已被调用。你不能用任何旧功能做到这一点;它必须为此而设计。第二个系统要求每个人都使用你的新功能而没有人使用旧功能。如果有人直接使用旧代码,您的代码将无法了解它。
第一种方法称为“侵入式”(因为它要求您以特殊方式编写对象),使用它的智能指针称为“侵入式智能指针”。第二种方法是非侵入式的(不需要对象的特殊代码)。 shared_ptr
和所有当前标准的智能指针都是非侵入式的。这意味着您可以将它们与任何对象一起使用,但只有遵守合同才能使用它们。
C ++不提供第三种方式。因此,一个可以以某种方式介入析构函数调用的类,一个可以知道它的类已被调用,而没有析构函数明确告诉它已经存在,是不可能的。因此会很神奇。