use*_*979 4 c++ memory-leaks c++11
在一次谈话中,以下代码已被证明是不安全的,因为如果构造函数抛出,则不会调用析构函数并泄漏资源:
class TwoResources {
TwoResources(int x, int y)
: m_a(nullptr), m_b(nullptr) {
m_a = new A(x); m_b = new B(y);
}
~TwoResources() {
delete m_b; delete m_a;
}
A * m_a; B * m_b;
};
Run Code Online (Sandbox Code Playgroud)
建议解决方案是使用委托构造函数,如下所示:
class TwoResources {
TwoResources() : m_a(nullptr), m_b(nullptr) { }
TwoResources(int x, int y) : TwoResources() {
m_a = new A(x); m_b = new B(y);
}
~TwoResources() {
delete m_b; delete m_a;
}
A * m_a; B * m_b;
};
Run Code Online (Sandbox Code Playgroud)
这是安全的,因为:
C++ 11 15.2 [except.ctor]/2:"如果对象的非委托构造函数已完成执行,并且该对象的委托构造函数存在异常,则将调用该对象的析构函数."
但是在同一张幻灯片中,它说:
仅仅因为你可以利用这条规则并不意味着你应该这样做!
如果这个代码保证是安全的,那么它有哪些潜在的问题呢?
只是因为某些东西是安全的并不意味着这样做是个好主意.
例如,使用该委托构造函数调用对于异常安全至关重要,但对于不熟悉该语言错综复杂的代码的随意读者来说,这一点并不明确.一个月后,看到你的代码的其他人可能会想"如果你再次在构造函数体中设置它,为什么要将它设置为null?" 并删除它.哎哟.
此外,当您手动管理生命周期时,您需要编写自己的复制/移动构造函数/赋值运算符.小姐和破坏结果.如果使用a unique_ptr来管理生命周期,那么编译器生成的移动构造函数/赋值运算符和析构函数将执行正确的操作,如果您尝试复制而不自行实现复制构造函数,它将会抱怨.
| 归档时间: |
|
| 查看次数: |
152 次 |
| 最近记录: |