【问题标题】:shared_ptr strangeness with null values and custom deleter具有空值和自定义删除器的 shared_ptr 陌生性
【发布时间】:2017-08-04 05:30:09
【问题描述】:

我们最近在使用自定义删除器从 unique_ptr 移动到 shared_ptr 时遇到了崩溃。当用于创建智能指针的指针为空时,就会发生崩溃。下面是重现问题的代码,并显示了两种可行的情况。

在下面的源代码中,一和二快乐地运行,而三在“ReleaseDestroy”中崩溃。当智能指针中使用的类具有虚拟“Release”时,崩溃似乎正在发生,因此程序正在尝试查找 V-Table。 unique_ptr 看起来像是检查空指针并且不运行析构函数。共享指针似乎忽略了这一点。

有谁知道这是设计使然,还是 stl 实现中的错误?我们正在使用 Visual Studio 2015。

#include <iostream>
#include <memory>

template<class R>
void ReleaseDestroy(R* r)
{
    r->Release();
};

class FlatDestroy
{
public :
    void Release()
    {
        delete this;
    }
};

class VirtualDestroy
{
public:
    virtual void Release()
    {
        delete this;
    }
};

class SimpleOne
{
public :
};

void main()
{
    std::shared_ptr<SimpleOne> One(nullptr);
    std::shared_ptr<FlatDestroy> Two(nullptr, ReleaseDestroy<FlatDestroy>);
    std::shared_ptr<VirtualDestroy> Three(nullptr, ReleaseDestroy<VirtualDestroy>);

    One.reset();
    Two.reset();
    Three.reset();
}

【问题讨论】:

    标签: c++ shared-ptr unique-ptr


    【解决方案1】:

    unique_ptrshared_ptr的破坏行为不同:

    • unique_ptr 仅在其持有的指针非空时才调用删除器。

    • shared_ptr 总是调用删除器。

    所以你的共享指针删除器必须能够处理空指针值!例如,std::free 可以,但 std::fclose 不行,你的删除器也不是(因为它无条件地取消引用 r)。

    顺便说一句,这在LWG 2415 中出现,它解决了从唯一指针构造共享指针的问题,正是由于这个原因,该指针在解决缺陷之前就被破坏了。 (我自己遇到了这个问题here;请注意该代码如何小心区分shared_ptr 的空大小写。)

    【讨论】:

    • “因为它无条件地取消引用 r”:所以第三种情况崩溃了,因为它试图通过“不存在”的 vtable 间接,而在第二种情况下没有这样的表应该在那里,对吗?
    • @A.S.H:这两种情况都在取消引用空指针,这会导致未定义的行为。
    • 实验表明是不同的(至少在Visual C++ 2015中),但是为什么呢?这是标准的一部分吗?有什么原因吗?使这些不同的原因是什么?真正的问题是,如果您将指针从 unique_ptr 转移到 shared_ptr,并且它为 null,shared_ptr 现在会崩溃,即使它们使用相同的自定义析构函数。
    • 阅读了您的参考资料 LWG 2415,看来问题是设计缺陷。
    • @SimonParker: shared from unique 的构造在修复之前肯定是有缺陷的。不同的行为可能是故意的;请记住,共享指针类型擦除删除器,因此无条件调用它提供了一点额外的灵活性。但我没有看过最初的设计原理。
    猜你喜欢
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多