c++删除/析构函数安全调用

C++ delete/destructor safe call

本文关键字:安全 调用 析构函数 删除 c++      更新时间:2023-10-16

我有一个"扭曲"的问题…假设有一个像

这样的类
class MyClass {
public:
 MyClass();
 ~MyClass();
MyClass& operator=(const MyClass& obj); 
private:
  int* mem;
};

基本上,MyClass以某种方式初始化mem(通过new调用),~MyClass()delete操作符释放mem。再假设操作符=重载了代码

MyClass& operator=(const MyClass& obj) {
 if(this != &obj) {
   //allocate memory of "this" with the "new" operator and copy "obj" data;
 }
return *this;
}
我的问题基本上如下…使用以下语句序列
//statement 1 for short
MyClass my_obj = some_obj_of_MyClass;

我猜一切都很好,因为操作符=分配内存并复制数据,但是下面的

//statement 2 for short
MyClass obj; //allocate memory for "mem" 
obj = some_obj_of_MyClass;

如果认为这是不正确的实现,我建议,因为我不删除内存分配的早期。我可以在赋值操作符块中调用析构函数,但在这种情况下,语句1可能不安全。

那么实现一切的安全方式是什么呢?我猜这里的问题可能是理解何时调用析构函数或如何正确实现它。

您的代码违反了第三条规则:

  1. 拷贝构造函数
  2. 复制赋值操作符
  3. 析构函数

它应该提供所有这三个。因为,如果省略了其中的任何一个,就有可能构造出发生不良事件的用例。例如,与直觉相反,语句

MyClass my_obj = some_obj_of_MyClass;

不调用赋值操作符。它调用您没有提供的复制构造函数。因此,使用默认的复制构造函数,它只是复制指针。一旦my_objsome_obj_of_MyClass被销毁,另一个将有一个指针指向被删除的内存区域。

另一方面,语句
MyClass obj;
obj = some_obj_of_MyClass;

将首先默认构造obj,然后对其调用赋值操作符。赋值操作符必须在obj的每一种可能状态下都能正确地工作(即它不能泄漏内存或双删除内存)。也就是说,如果分配了obj.mem,则赋值操作符必须重用该内存或释放它(可能用新的分配替换它)。如果obj.mem可以是空指针,那么赋值操作符必须包含对这种特殊情况的特殊处理。

所以,你的选择基本上是,你是否想让mem指针成为一个空指针,如果你不允许,你的默认构造函数必须分配一个虚拟的内存区域,可以通过赋值操作符释放。


您还可以通过删除未实现的函数来绕过三规则。你的类可以这样声明:

class MyClass {
public:
    MyClass();
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass& obj); 
    ~MyClass();
private:
    int* mem;
};

这将禁止语句

MyClass my_obj = some_obj_of_MyClass;

强制用户代码使用更详细的

MyClass obj;
obj = some_obj_of_MyClass;

,但这使得MyClass的实现更简单。