【问题标题】:Class pointer members and exception handling类指针成员和异常处理
【发布时间】:2017-04-04 07:14:34
【问题描述】:

假设我们有一个像下面这样的类:

class A {
    public:
        A();
        ~A();
        void foo();
        int* pointer;
};

A::A() {
    pointer = new int;
}

A::~A() {
    delete pointer;
}

A::foo() {
     throw "error";
}

以及使用它的以下示例:

示例 1

int main() {
    A a;
    throw "error";

    return 0;
}

示例 2

int main() {
    A a;
    a.foo();

    return 0;
}

在这两种情况下,都会出现内存泄漏,因为 A 的析构函数由于未处理的异常而永远不会被调用。

我的问题是类的用户是否有责任确保通过处理异常来调用析构函数:在第一个示例中,异常与类无关,所以我认为责任在于类的用户,但在第二个例子中,类本身抛出错误 - 是否仍然由类的用户来确保正确处理异常,或者这仅仅是类本身的糟糕设计?

【问题讨论】:

    标签: c++ pointers memory-management memory-leaks exception-handling


    【解决方案1】:

    这无关紧要。存在“内存泄漏”的唯一原因是程序将结束,这通常会清理内存。

    无论如何,如果程序由于未处理的异常而退出,这不是类的问题。想象一下,如果您有 100 个类,所有这些类都需要关心一个函数 (main) 是否无法处理异常。

    【讨论】:

      【解决方案2】:
      void throw();
      

      这不会编译。 throw 是保留关键字。

      暂时忽略这个细节,你最初的假设并不完全正确。

      在这种情况下,异常没有被捕获,程序将终止,所以内存泄漏是学术性的。

      但是,如果在范围内有一个try/catch 块,它将捕获异常,在任何一种情况下都不会出现内存泄漏。在这两个示例中,a 对象已完全构建。因此,抛出的异常将销毁a,并调用其析构函数。

      抛出的异常将展开堆栈,直到捕获到异常,并且作为该过程的一部分,销毁本地范围内的所有对象,直到捕获到异常。

      所以,这是一个有争议的问题。只要异常最终被捕获,就没有内存泄漏,没有人需要担心任何事情。

      您展示的类大部分符合RAII 原则(需要一个复制构造函数和一个赋值运算符,以结束松散的部分)。该类唯一负责的就是如果在构造函数中抛出异常,无论构造函数分配了什么都需要清理。

      【讨论】:

      • 是的,没错,添加了轻微的调整。
      猜你喜欢
      • 1970-01-01
      • 2021-11-08
      • 1970-01-01
      • 2016-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多