C++11 为什么共享ptr不';发生异常时,不要调用指针的析构函数

C++11 为什么共享ptr不';发生异常时,不要调用指针的析构函数,c++11,shared-ptr,C++11,Shared Ptr,我测试了C++11 shared_ptr,感到很惊讶 在这个例子中 #include <iostream> #include <vector> #include <memory> #include <string> #include <exception> using namespace std; class MyExc { }; class Slot { public: Slot(const std::string &

我测试了C++11 shared_ptr,感到很惊讶 在这个例子中

#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <exception>

using namespace std;

class MyExc
{

};

class Slot
{
public:
    Slot(const std::string &str = "NONAME") : m_name(str)
    {
        cout << "Constructor of slot: " << m_name << endl;
    }

    virtual ~Slot()
    {
        cout << "Destructor of slot: " << m_name << endl;
    }

    void sayName()
    {
        cout << "Slot name is: " << m_name << endl;
//       throw MyExc();
    }

private:
    string m_name;
};


void testShared(shared_ptr<Slot> & m_share)
{
    m_share->sayName();
}

int main()
{
    vector<shared_ptr<Slot>> vec {make_shared<Slot>("0"), make_shared<Slot>("1"), make_shared<Slot>("2"), make_shared<Slot>("3"), make_shared<Slot>("4")};
    for (auto& x:vec)
        testShared(x);


    return 0;
}
输出已更改,并且未显示析构函数调用消息

在抛出“MyExc”实例后调用terminate 插槽的构造函数:0
插槽的构造函数:1
插槽的构造函数:2
插槽的构造函数:3
插槽的构造函数:4
插槽名称为:0


这是否意味着内存泄漏被放置在这里?

在您的情况下,是的,存在内存泄漏(这并不重要,因为程序将立即终止,操作系统将回收内存)

要消除这种情况,您需要知道,只有在捕获异常时,标准才能保证堆栈展开(即在调用堆栈上升时销毁局部变量)。如果从未捕获到异常并直接转到
std::terminate
,则是否展开取决于编译器和标准库

引用C++11:

15.2:

1当控件从抛出表达式传递到处理程序时,将为所有自动对象调用析构函数 自输入try块后构造。自动对象的销毁顺序与 完成他们的建设

3为从try块到try块的路径上构造的自动对象调用析构函数的过程 抛出表达式称为“堆栈展开”

15.3:

9如果没有找到匹配的处理程序,则调用函数
std::terminate()
;不管堆栈是否为空 在对
std::terminate()
的调用被定义为实现之前展开(15.5.1)


谢谢,如果我修改代码为:for(auto&x:vec){try{testShared(x);}catch(MyExc&ex){exit;}>所有工作正常,输出为:插槽构造函数:0插槽构造函数:1插槽构造函数:2插槽构造函数:3插槽构造函数:4插槽名称为:0插槽名称为:1插槽名称为:2插槽名称为:3插槽名称为:4插槽析构函数:0插槽析构函数:1插槽析构函数:2插槽析构函数:3 Dslot:4Perhaps的Esstructor值得一提的是它这样工作的一个原因:通常,如果异常未经处理,程序(或实际上是操作系统)会选择性地保存一个崩溃转储,允许开发人员在调试器中加载该崩溃转储并找出错误所在。这通常对最终用户并不重要(无论哪种方式,程序都崩溃了),如果不展开堆栈,就可以直接指向引发异常的位置,并且所有局部变量都保持不变,从而使调试对开发人员更加友好。
throw MyExc();