2

我在 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;
}

这将打印/保存已删除的对象的数据成员,而不会报告任何类型的错误。

请写在:

  1. 为什么shared_ptrpObj 不报告(在运行时)底层对象已被删除?
  2. 由于我正在创建一个 const shared_ptr,意味着不能使用它来引用任何其他对象,为什么在对象删除时不调用 lambda。
  3. weak_ptr在类似情况下可能会有所帮助。weak_ptr与对对象的引用的生命周期超过它所引用的对象的语义一起使用。
4

1 回答 1

20

为什么 shared_ptr pObj 不报告(在运行时)底层对象已被删除?

因为shared_ptr不是魔法1只有在删除该对象时,它才知道包含的对象何时被删除。当您使用 时shared_ptr,您已与 签订合同shared_ptr。该合同的租户之一(实际上,您使用任何类型的智能指针签订的任何合同)是无法删除该指针。shared_ptr实例拥有指针,会删除它,而不是你。

违反该合同会导致未定义的行为。

由于我正在创建一个 const shared_ptr,意味着不能使用它来引用任何其他对象,为什么在对象删除时不调用 lambda。

同样,只有在删除shared_ptr时才能知道包含的对象被删除。如果您违反合同,它对对象的状态一无所知。

在类似情况下,weak_ptr 是否有帮助。weak_ptr 与对对象的引用的生命周期超过它所引用的对象的语义一起使用。

weak_ptr没有比 更神奇的天赋shared_ptrweak_ptr只知道shared_ptr创建它的集合知道什么。如果shared_ptr不知道对象已被删除,则也不知道weak_ptr


1 “魔术”是指做一些在 C++ 中不可能的事情。如果您想知道一个函数是否被调用(而析构函数是一个函数调用),那么只有两种方法可以做到这一点。要么该函数告诉您它已被调用(通过设置您可以看到的一些值),要么您设置了一个系统,人们调用您的函数,然后调用另一个函数。

第一个系统需要一个明确编写的函数,让人们知道它已被调用。任何旧功能都无法做到这一点;它必须为此而设计。第二个系统要求每个人都使用您的新功能,而没有人使用旧功能。如果有人直接使用旧的,您的代码将不知道它。

第一种方法称为“侵入式”(因为它要求您以特殊方式编写对象),使用它的智能指针称为“侵入式智能指针”。第二种方法是非侵入式的(不需要对象的特殊代码)。shared_ptr,以及所有当前标准的智能指针,都是非侵入式的。这意味着您可以将它们与任何对象一起使用,但您只能在遵守合同的情况下使用它们。

C++ 不提供第三种方式。因此,一个可以以某种方式侵入析构函数调用的类,一个可以知道它已被调用而没有该析构函数明确告诉它已经被调用的类,是不可能的。因此会很神奇。

于 2013-04-05T10:08:44.983 回答