C++ c++;遇到异常时构造函数中的可用内存分配

C++ c++;遇到异常时构造函数中的可用内存分配,c++,exception,memory,memory-management,constructor,C++,Exception,Memory,Memory Management,Constructor,在构造对象时出现异常的情况下,我发现了一些有趣的行为: class bookentry { public: bookentry(){ t1.reset(new test1); //0 test1 *t11 = new test1; //1 test2 *t22 = new test2; //2 throw 1; //3 } protected: private: au

在构造对象时出现异常的情况下,我发现了一些有趣的行为:

class bookentry
{
public:
    bookentry(){
      t1.reset(new test1);       //0 
      test1 *t11 = new test1;    //1
      test2 *t22 = new test2;    //2
      throw 1;                   //3
    }
protected:
private:
  auto_ptr<test1> t1;
  auto_ptr<test2> t2;
};
分类簿记
{
公众:
簿记(){
t1.重置(新测试1);//0
test1*t11=新的test1;//1
test2*t22=新的test2;//2
抛出1;//3
}
受保护的:
私人:
自动ptr t1;
自动ptr t2;
};
根据我的测试:

如果我们从test2的构造函数(#2)抛出异常,那么

  • t1:将被完全销毁,即调用t1的析构函数,并释放内存
  • t11:将永远不会被销毁(既不调用t11的析构函数也不释放内存)
  • t22:这是有趣的部分,t22的析构函数将不会被调用,这是正确的,但是t22的内存将被释放
  • 如果我们从bookentry的构造函数(#3)抛出一个异常,这一次,情况会有一点不同:t22将永远不会被销毁(既不会调用t22的析构函数也不会释放内存),t11与上面相同

    我只是对第二句的句子感到困惑

    test2*t22=新的test2//二,

    看起来,当我们从类构造函数中抛出异常时,新表达式将确保调用相应的delete,但是在该异常之前通过新表达式完全创建的任何对象都将泄漏(如果我们在#3处抛出异常,则为t11和t22)

    因此,如果我们编写如下代码,第五个对象构造失败:

    test2*t2s=新的test2[10]

    然后,看起来更安全一点:

  • 已经建造的物体将被摧毁
  • 内存将被释放
  • 我的问题,这是标准C++行为吗?我刚刚测试了MSVC2012和GCC4.4.6,它们看起来都实现了这样的机制

    编辑 为了更清楚地回答我的问题:

    在某些情况下,您需要在其他正常函数中编写类似t1.reset(新test1)的代码[参见我的代码中的#1]。在这种情况下,如果构造函数抛出异常。我如何解释程序状态?有内存泄漏吗

    <强>我的测试确保< /强>在这种情况下,没有内存泄漏,但它是标准C++行为吗?< /P> < P>规则很简单:
    在该范围内完全创建的所有对象将被销毁
    上述规则不适用于指向在动态存储上分配的对象(使用

    new
    分配)的原始指针。它们需要显式地
    delete
    d。使用
    new
    时,您明确拥有资源管理,您的工作是调用
    delete
    来释放资源,而编译器不会为您这样做


    读得好:



    <>注意,C++中管理资源的最佳方法是使用RAII和智能指针。在构造函数中更是如此。不使用任何原始指针,只需将它们封装在智能指针中,它们就会自动为您的对象进行资源管理,以防出现此类异常。当您在代码示例中使用
    auto_ptr
    而不是原始指针时,您刚刚体验到了这种能力

    MSVC 2012明确支持
    std::unique_ptr
    std::shared_ptr
    。我敢打赌,GCC版本也会这样做。只要有可能,就使用它们,而不是
    std::auto_ptr
    ,因为它现在已被弃用。不,你不明白我的问题。在某些情况下,您需要编写类似t1.reset(新test1)的代码,请参见我的代码中的#1,这可能在其他正常函数中。在这种情况下,如果从构造函数引发异常。我如何解释程序状态?有内存泄漏吗?@Chang:你还没有读过答案或答案中的链接。如果你这样做了,你会找到你问题的答案。我绝对读过那篇文章,不是现在,也是10年前。C++标准被改变了两次(03和11)。在示例2b中,如果初始值设定项列表中只有一个新表达式,那么它现在似乎是安全的。Re:“上述规则不适用于原始指针”-另一种理解方式是,该规则确实适用于原始指针;指针的析构函数不执行任何操作。