处理失败的构造函数
handling failing constructors
我正在从常见问题解答中读取失败C++构造函数,但不理解以下代码。
void f()
{
X x; ← if X::X() throws, the memory for x itself will not leak
Y* p = new Y(); ← if Y::Y() throws, the memory for *p itself will not leak
}
如果构造函数抛出,p 指向的内存怎么可能不泄漏?我假设顺序如下。
- 为对象 Y 分配内存。
- 调用 Y 的构造函数。
- Y 的构造函数抛出和 p 泄漏指向的内存。
构造函数抛出,则堆栈将展开,包括删除分配给 Y 的内存。
问题主要出现在/如果您有多个对象要处理时。例如:
void f() {
X *x = new X();
Y *y = new Y();
}
现在,如果new X()
部分成功,但new Y()
部分失败,则分配给y
的内存将被删除,但x
不会被销毁,其内存将被泄漏。如果你真的坚持,你可以用try
块来解决这个问题:
try {
X *x = new X();
Y * y = new Y();
}
catch (y_construction_failed) {
delete x;
}
这样做的最大问题是,如果你有两个以上的项目,你必须嵌套try
块,所以如果你需要,比如说,六个局部变量,它将是深深嵌套的,而且非常丑陋。
你会遇到一个类似的问题,函数void f(X*, Y*)并调用f(new X(),new Y())。如果其中一个新调用成功,而另一个失败,则存在内存泄漏。要解决此问题,您可以创建其他函数"X* make_X()"和"Y* make_Y()"返回指针。现在,f(make_X(),make_Y())是安全的。(走那么远之后,你可能会使用智能指针)
请务必注意,即使删除了对象,在这种情况下也不会调用其析构函数。
这是有道理的,因为构造期间的异常表明对象从未完全构造过(即尚未建立其类不变量),因此调用析构函数可能是危险的。
这样做的缺点是,如果构造函数执行的操作需要清理,而这些操作通常由析构函数执行,则构造函数现在负责在发生异常时执行此清理。举个例子:
class C {
private:
int* p1;
int* p2;
public:
C() : p1(new int()), p2(new int()) {}
~C() { delete p1; delete p2; }
};
如果抛出分配p2
,则已分配给p1
的内存将泄漏。作为程序员,您有责任以不可能发生的方式编写构造函数。
实现此目的的最简单方法是将资源管理职责委托给 RAII 容器类,如 unique_ptr
。这样,没有类负责管理多个资源,并且不会再发生上述情况。
- 为什么除非添加括号,否则构造函数上的模板替换会失败?
- 在构造函数中分配内存失败是如何冒泡的
- 函数返回时,带指针的复制构造函数失败
- MPICH 的 MPI_Comm_dup() 在复制构造函数中失败
- 引用构造函数时链接失败
- 类模板在其构造函数中的模板变量推导失败
- 构造函数SFINAE和继承在clang中失败
- 为什么即使直接构造函数有效,template_back也会失败
- 在 if 语句中调用重载构造函数失败
- 继承的构造函数,在 clang++3.9 中编译,在 g++ 7 中失败
- C++模板化类默认构造函数失败
- STD :: MAP EMPLECE通过显式构造函数失败
- 打开不存在的文件时如何使流构造函数失败?
- 复制构造函数失败..重载,动态分配
- 如何处理 RAII 的构造函数失败
- C++unique_ptr作为成员的模板的构造函数失败
- 如何使用new(std::nothrow)使构造函数失败
- 在stl列表中调用构造函数失败
- 尽管类名与C++完全匹配,但模板基类初始化构造函数失败
- 尝试在类成员初始化中使用 vector 的填充构造函数失败。怎么了?