如果delete [] p失败会怎么样?

fre*_*low 20 c++ arrays memory-leaks exception resource-management

假设我有一个指向动态分配的10个元素数组的指针:

T* p = new T[10];
Run Code Online (Sandbox Code Playgroud)

后来,我想发布那个数组:

delete[] p;
Run Code Online (Sandbox Code Playgroud)

如果其中一个T析构函数抛出异常会发生什么?其他元素是否仍然被破坏?记忆会被释放吗?是否会传播异常,还是会终止程序执行?

同样地,当一个std::vector<T>被破坏而其中一个T析构者抛出时会发生什么?

Mar*_*ork 6

我无法在标准中明确地看到它:

只是他们将以创建的相反顺序被调用

5.3.5删除[expr.delete]

6如果delete-expression的操作数的值不是空指针值,则delete-expression将调用对象的析构函数(如果有)或要删除的数组的元素.在数组的情况下,元素将按地址递减的顺序销毁(即,与构造函数完成的顺序相反;见12.6.2).

并且即使抛出异常,也会完成内存释放:

7如果delete-expression的操作数值不是空指针值,则delete-expression将调用释放函数(3.7.4.2).否则,未指定是否将调用释放功能.[ 注意:无论对象的析构函数或数组的某个元素是否引发异常,都会调用释放函数.- 结束说明 ]

我在G ++中尝试了以下代码,它表明在异常之后不再调用析构函数:

#include <iostream>
int id = 0;
class X
{
    public:
         X() {   me = id++; std::cout << "C: Start" << me << "\n";}
        ~X() {   std::cout << "C: Done " << me << "\n";
                 if (me == 5) {throw int(1);}
             }
    private:
        int me;
};

int main()
{
    try
    {
        X       data[10];
    }
    catch(...)
    {
        std::cout << "Finished\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

执行:

> g++ de.cpp
> ./a.out
C: Start0
C: Start1
C: Start2
C: Start3
C: Start4
C: Start5
C: Start6
C: Start7
C: Start8
C: Start9
C: Done 9
C: Done 8
C: Done 7
C: Done 6
C: Done 5
Finished
Run Code Online (Sandbox Code Playgroud)

这一切都回到了这个(非常古老的答案):
从析构函数中抛出异常


Seb*_*ach 5

永远不要那样做.如果已经存在活动异常,std::terminate则会被称为:"砰,你死了".你的析构函数必须.不.扔.抗.


编辑:标准的相关部分(14882 2003),15.2构造函数和析构函数[except.dtor]:

15.2.3 为从try块到throw-expression的路径构造的自动对象调用析构函数的过程称为"堆栈展开".[注意:如果在堆栈展开期间调用的析构函数以异常退出,则调用terminate( 15.5.1).所以析构函数通常应该捕获异常,而不是让它们从析构函数中传播出来. - 尾注]


玩游戏的测试用例(在现实生活中,抛出衍生出来的东西std::exception,永远不要扔int或其他东西!):

    #include <iostream>
    int main() {
        struct Foo {
            ~Foo() {
                throw 0; // ... fore, std::terminate is called.
            }
        };

        try {
            Foo f;
            throw 0; // First one, will be the active exception once Foo::~Foo()
                     // is executed, there- ...
        } catch (int) {
            std::cout << "caught something" << std::endl;
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • @phresnel:所有这些都是正确的,为什么析构函数不应该抛出异常,但是不回答这个问题. (4认同)
  • 仅在堆栈展开期间. (2认同)
  • 我相信只有在由于另一个异常导致堆栈被解除时调用析构函数时才会发生这种情况.但当然,不要在析构函数中使用异常是一个很好的论据. (2认同)
  • 这不回答这个问题."如果已经有一个活跃的例外":但是没有!并且在正常代码中删除[] p`(即在析构函数之外)与堆栈展开无关. (2认同)

Tad*_*pec 5

5.3.5.7如果delete-expression的操作数值不是空指针值,则delete-expression将调用解除分配函数(3.7.3.2).否则,是否未调用是否将调用释放功能.[注意:无论对象的析构函数或数组的某个元素是否引发异常,都会调用释放函数. - 结束说明]

找不到任何关于析构函数的内容除外

在数组的情况下,元素将按地址递减的顺序销毁(即,与构造函数完成的顺序相反;见12.6.2).

我想投掷后没有更多的析构函数被调用,但我不确定.