在使用c++ 11智能指针时,你能忘记检查删除吗?



我读过不完整类型的unique_ptr和Checked Delete。但是,当使用智能指针,或者至少是c++ 11智能指针的一个子集时,检查删除是否已经过时了?

取以下代码:

class A;
class B
{
public:
    std::auto_ptr<A> autoPtr;
    std::unique_ptr<A> uniquePtr;
    std::shared_ptr<A> sharedPtr;
    A* rawPtr;
    B();
    ~B(){delete rawPtr;}
};
class A
{
public:
    ~A(){std::cout << "~A" << std::endl;}
};
B::B()
{
    autoPtr = std::auto_ptr<A>(new A());
    uniquePtr = std::unique_ptr<A>(new A());
    sharedPtr = std::shared_ptr<A>(new A());
    rawPtr = new A();
}
B b;
当定义了B的析构函数时,A的类型仍然是不完整的。据我所知[c++ 11标准@ [expr.delete]]原始指针的删除是未定义的行为。在我的机器上,gcc 4.8显示了一些关于这个的警告,但是编译和A的析构函数没有被正确调用。

但是智能指针呢?正如我所读到的,unique_ptr和shared_ptr必须根据c++11标准工作。但是两个链接的文档都声明auto_ptr不起作用。但至少在我的gcc 4.8中,auto_ptr也正确地调用析构函数,没有任何警告。这仍然是未定义的行为和gcc只是好吗?

简而言之:根据c++ 11标准,四个成员变量中哪一个保证使用稍后定义的析构函数适当地销毁其a指针?

最后:如果我只使用unique_ptr和shared_ptr,从不调用"删除"自己,我是安全的,永远不需要考虑"检查删除"了吗?

对于shared_ptr,重要的是当您将指针传递给shared_ptr时类型是否完整(通常应该是这样,因为您刚刚创建了A)。此时,shared_ptr将创建某种类型的删除器,它需要完整类型,并将其存储起来,以便在引用计数下降到零时可用(即使这发生在A不完整的文件中)。

对于unique_ptr,重要的是在调用default_delete时类型是否完成,这通常在unique_ptr析构函数中(但也可以在reset()成员或赋值操作符中)。

对于不完全类型使用auto_ptr是没有定义的。

回答题目中的问题:标准要求shared_ptrunique_ptr将拒绝编译试图删除不完整类型的代码。这并不能保证100%的安全,因为如果base没有虚析构函数,执行unique_ptr<base>(new derived)仍然可能有未定义的行为。

我认为允许代码编译的原因是GCC在文件末尾实例化模板,并且在定义b之前不需要内联B析构函数,此时A已经完成。如果你把AB::B的定义与变量b放在一个单独的文件中,那么你会发现当b被销毁时,unique_ptr不会正确地删除A(事实上,它甚至不应该编译,因为销毁b调用default_delete,而标准说这需要一个完整的类型,否则程序是病态的)。

可移植的解决方案是确保在为B定义析构函数的地方A是完整的,因此,如果A不是在所有文件中都完整,则不要内联地定义析构函数。

相关内容

  • 没有找到相关文章

最新更新