【问题标题】:some questions on exception safety and memory leaks关于异常安全和内存泄漏的一些问题
【发布时间】:2013-09-20 16:58:11
【问题描述】:

如果我有一个类A 并且某个主体使用我的代码创建A 的对象,然后在没有try-catch 的情况下调用DoSth(),内存会泄漏吗?在 valgrind 的报告中可能丢失并且仍然可以访问是否表明内存泄漏?如果没有,如何避免它们?更何况A的构造函数也不安全吧?我必须使用 智能指针 来替换原始指针 Animal* 吗?还有一种策略叫“copy-and-swap”,什么时候用呢?由于 operator new 可能会抛出异常,所以当我想在堆上动态分配内存时,我有点困惑。

代码

class A
{
public:
    A(const string& petname, int petage)
        :pet_(new Animal(petname, petage))
    {

    }

    ~A()
    {
        delete pet_;
    }

    void DoSth()
    {
        // do sth...
        throw;
    }

private:
    Animal* pet_;
};

int main(int argc, char const *argv[])
{
    A a("Kitty", 3);
    a.DoSth();
    return 0;
}

Valgrind 报告

==2799== LEAK SUMMARY:
==2799==    definitely lost: 0 bytes in 0 blocks
==2799==    indirectly lost: 0 bytes in 0 blocks
==2799==      possibly lost: 30 bytes in 1 blocks
==2799==    still reachable: 16 bytes in 1 blocks
==2799==         suppressed: 0 bytes in 0 blocks

【问题讨论】:

  • 在这种情况下:否,因为“a”是堆栈分配的,当异常会导致堆栈展开时将被释放(调用其析构函数)。如果在堆上分配“a”(或者如果您在“DoSth()”中分配内存但由于异常而没有释放它),您可能会发生泄漏。
  • 为什么要在堆上分配Animal 对象?
  • @ZacHowland 这只是一个演示,用于模拟具有指针数据成员的类的情况。而且这个类可能会在运行时抛出异常。

标签: c++ exception memory-leaks valgrind


【解决方案1】:

Valgrind 的报告显示潜在的内存泄漏,因为您让异常冒泡到应用程序级别,这会杀死应用程序。然后释放资源。

不过,有几点需要注意:

1) 如果一个函数有可能抛出异常,您应该在该异常到达应用程序级别之前处理该异常(在该级别,异常将杀死您的应用程序 - 异常的想法是允许您处理错误优雅地)。

2) 为什么要在堆上分配Animal?在此设置中,它可以很容易地分配到堆栈上,在这种情况下,您也不会在 Valgrind 中显示潜在的泄漏。

如果您担心new 抛出异常(实际上,这通常仅在您分配的内存不足时才会发生......所以不经常发生),您需要在单独的函数中定义您的初始化(即使是智能指针也不会为您避免这个问题),或者在构造函数中有一个 try-catch 块,或者不要将 Animal 放在堆上。

【讨论】:

  • 谢谢!扎克·豪兰。在阅读了“Effective C++”中关于异常安全的章节之后,我开始关注我的代码。现在,我感觉好多了……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多