C++ 非完全构造的对象释放

c++ non fully constructed object deallocation

本文关键字:对象 释放 C++      更新时间:2023-10-16

代码 :

#include<iostream>
using namespace std;
class A{
public:
A(){cout << "A() Constructor " << endl;
throw 1;
}
};

int main(){
A* p=0;
cout << p << endl; // p value is 0
try{
p=new A(); // object is not fully constructed, no address is returned to p. for future deallocation
}
catch(...){cout << "Exception" << endl;}
cout << p << endl; // this will output that p has the value 0,proof that no address was returned to p.

}

为堆中的对象分配内存,内存的地址传递给构造函数 但是当构造函数throw 1;时,类型A的对象将不被视为完全构造的对象。所以没有 指针将返回指针 P.如果我理解了错误,请随时纠正我。

问题:
1)所以我的问题是在这种情况下如何为A对象释放内存。我不是在谈论 析构函数调用,但内存的释放。

2)当我在函数内创建类型为A的本地对象时main呢?显然,它也不会完全构建。这个对象什么时候被释放(当然是在调用完全解释的子对象的析构函数之后)。

new A()完成的分配包括多个步骤:

  1. 使用operator new(sizeof(A))分配内存。
  2. 尝试默认在分配的内存中构造一个对象。
  3. 当默认构造失败时,将使用之前获取的地址调用operator delete(x)

更一般地说,如果你使用重载operator new(),例如,调用operator new(size_t, Alloctor)new(allocator) A()(其中allocator可转换为Allocator),则调用相应的operator delete()

作为异常抛出的一部分,所有部分构造的子对象也会被销毁(以与构造它们的顺序相反的顺序)。也就是说,如果从对象的构造函数中抛出异常,则无需关心清理(假设所有子对象都正确照顾它们分配的资源)。这与对象是在堆上还是在堆栈上分配无关。

1)为您完成分配。

2)如果它是一个本地对象,它从一开始就不会被分配。

当构造函数抛出为该对象分配的内存时,顺便说一句,不会调用析构函数。 您不需要解除分配。

在 CPP 中,构造函数(ctor) 调用的顺序为:

虚拟基
  • 类:虚拟基 CTOR,根据深度第一序列调用。
  • 基类:基类
  • 在定义类时根据派生声明调用序列。
  • 非静态成员对象
  • 派生类 ctor;

析构函数 (dtor) 按相反的顺序调用。

CPP 确保释放完全构造的对象(非指针)的资源。

有RAII(资源获取是初始化)。我们使用对象来包装原始指针来分配内存,然后在 dtor 中释放内存。如果派生对象由于(内存不足、异常等)而被部分构造,则将调用成员对象 dtor。

在上面的简单示例中,没有分配资源,因此没有资源泄漏。

但是,如果有成员指针在抛出之前分配内存,则会出现内存泄漏。如果我们将内存包装在一个类中并将此类的对象作为组件(使用 RAII),那么就不会有 内存泄漏 .