C++ 使用另一个指针对“unique_ptr”拥有的对象调用“delete”

C++ 使用另一个指针对“unique_ptr”拥有的对象调用“delete”,c++,c++11,smart-pointers,unique-ptr,delete-operator,C++,C++11,Smart Pointers,Unique Ptr,Delete Operator,我有一个指向由new操作符初始化的类的指针。然后我使用这个指针设置一个std::unique\u ptr。现在,据我所知,下面的代码有双重删除,一次手动调用delete操作符,然后当唯一指针超出范围时。该代码如何“正确”运行,即没有运行时异常 #include <iostream> #include <memory> class A { public: A() { std::cout<<"In A::A()\n"; }

我有一个指向由
new
操作符初始化的类的指针。然后我使用这个指针设置一个
std::unique\u ptr
。现在,据我所知,下面的代码有双重删除,一次手动调用
delete
操作符,然后当唯一指针超出范围时。该代码如何“正确”运行,即没有运行时异常

#include <iostream>
#include <memory>

class A
{
public:
    A()
    {
        std::cout<<"In A::A()\n";
    }
    ~A()
    {
        std::cout<<"In A::~A()\n";
    }
    void printMyStr()
    {
        std::cout<<"In A::printMyStr()\n";
    }
};

int main()
{
    std::cout<<"hello world!\n";
    A * pa = new A();
    std::unique_ptr<A> upa(pa);
    pa->printMyStr();
    upa->printMyStr();
    delete pa;  // How does this not create problems?
    return 0;
}
显然,析构函数运行两次,即使只创建了一个对象。这怎么可能


注意:我在64位linux上使用gcc 7.3.0。

双重删除是未定义的行为

未定义的行为不能保证运行时异常;这将被定义。未定义的行为意味着任何事情都可能发生。这可能包括时间旅行、格式化硬盘、通过电子邮件向联系人发送浏览器历史记录,或者什么都不做


据我所知,我还没有体验过通过电子邮件发送浏览器历史记录。我已经经历了剩下的。

双重删除是未定义的行为

未定义的行为不能保证运行时异常;这将被定义。未定义的行为意味着任何事情都可能发生。这可能包括时间旅行、格式化硬盘、通过电子邮件向联系人发送浏览器历史记录,或者什么都不做


据我所知,我还没有体验过通过电子邮件发送浏览器历史记录。我已经经历了其余的过程。

如果在唯一\u ptr实例超出范围之前的某个时间点,您决定删除托管对象,只需执行
unique\u ptr\u instance.reset(nullptr)
。这将调用删除程序并导致托管对象变为nullptr,当实例最终超出范围时删除该对象是不可操作的。

如果在unique_ptr实例超出范围之前的某个时刻,您决定删除托管对象,只需执行
unique_ptr_instance.reset(nullptr)
。这将调用deleter并导致托管对象变为null ptr,当实例最终超出范围时删除该对象是不可操作的。

这只是未定义的行为,而不是会引发异常的行为。如果您通过valgrind运行它,它应该会告诉您有一个问题。“这怎么可能?”对于未定义的行为,任何事情都是可能的。(包括“看起来正常工作”。)这只是未定义的行为,而不是引发异常的行为。如果您通过valgrind运行它,它应该会告诉您有一个问题。“这怎么可能?”对于未定义的行为,任何事情都是可能的。(包括“看起来工作正常”。)你真的体验过硬盘的格式化吗?@einpoklum我经历过文件系统因UB而损坏,尽管没有重新格式化。但没有理由不这样做。另一方面,“时间旅行”…@einpok是内存损坏,将错误的(垃圾)参数传递给(相当可怕的)文件系统API,清除HDD的格式,如果我没记错的话。但是是的,这是一个bug(与UB一起),其症状是“HDD丢失格式”。@Yakk AdamNevraumont:但这是一种欺骗。我的意思是,文件系统API的定义行为可能涉及删除内容。有一个2017年CppCon的演讲,Piotr Padlewski在会上解释了如何在不经意和意外的情况下实现这一点。@einp我不记得API到底是什么。可能是试图“创建临时文件”之类的。销毁驱动器不是function应该能够做的事情之一。我相信那是DOS时代,用户空间可以完全访问硬盘硬件。你真的体验过硬盘的格式化吗?@einpoklum我经历过UB导致的文件系统损坏,尽管没有重新格式化。但没有理由不这样做。另一方面,“时间旅行”…@einpok是内存损坏,将错误的(垃圾)参数传递给(相当可怕的)文件系统API,清除HDD的格式,如果我没记错的话。但是是的,这是一个bug(与UB一起),其症状是“HDD丢失格式”。@Yakk AdamNevraumont:但这是一种欺骗。我的意思是,文件系统API的定义行为可能涉及删除内容。有一个2017年CppCon的演讲,Piotr Padlewski在会上解释了如何在不经意和意外的情况下实现这一点。@einp我不记得API到底是什么。可能是试图“创建临时文件”之类的。销毁驱动器不是function应该能够做的事情之一。我相信那是DOS时代,用户空间可以完全访问硬盘。
hello world!
In A::A()
In A::printMyStr()
In A::printMyStr()
In A::~A()
In A::~A()