C++析构函数调用时机困惑及手动资源释放疑问
C++问题解答
错误原因
循环内部提前触发析构函数,核心问题是你的books类未遵循Rule of Three(三法则),且循环中存在对象拷贝/临时对象创建操作。
因为类里有动态分配的char*,默认的拷贝构造和拷贝赋值是浅拷贝——会让两个对象的指针指向同一块内存。如果循环里做了books temp = B[i];这类值拷贝操作,临时对象temp在循环结束时会被销毁,调用析构函数释放内存,导致原数组对象B[i]的指针变成野指针,后续访问自然失效。
让析构函数仅在main结束时调用的方法
1. 实现深拷贝的拷贝构造与拷贝赋值
必须手动实现深拷贝逻辑,确保每个对象拥有独立的内存空间:
// 拷贝构造函数 books(const books& other) { // 分配足够内存存储字符串 this->str = new char[strlen(other.str) + 1]; strcpy(this->str, other.str); } // 拷贝赋值运算符 books& operator=(const books& other) { if (this != &other) { // 防止自赋值导致的内存泄漏 // 先释放当前对象的内存 delete[] this->str; // 深拷贝新内容 this->str = new char[strlen(other.str) + 1]; strcpy(this->str, other.str); } return *this; }
这样循环中做对象拷贝时,临时对象会拥有独立的内存副本,它的析构不会影响原数组对象,原数组的析构函数只会在main结束、销毁数组B时被调用。
2. 避免不必要的对象拷贝
循环里尽量用引用或指针操作数组对象,比如books& ref = B[i];,这样不会生成临时对象,也就不会触发额外的析构。
关于自定义destroybooks函数的问题
如果destroybooks仅用于释放对象内部的char*内存(比如:
void destroybooks(books& b) { delete[] b.str; b.str = nullptr; }
),最后仍然必须执行delete []B:
destroybooks只释放了对象内部的字符串内存,但数组B本身是用new[]分配的对象实例内存(比如char*指针变量占用的空间),这块内存必须通过delete[] B回收,否则会造成对象实例的内存泄漏。- 另外要确保析构函数里判断
str是否为nullptr再释放,避免重复释放:
~books() { if (str != nullptr) { delete[] str; } }
内容的提问来源于stack exchange,提问作者Vinayak Deshmukh
相关产品推荐
相关产品推荐

