You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++ for循环中析构函数被多次调用?它销毁的是哪些对象?

C++ vector元素构造/析构异常问题解析

问题代码

#include <iostream>
#include <vector>

using namespace std;

class Testing{
    
    private:
        bool    object_alive;
        int     object_id;

    public:
        Testing(bool alive, int id);
        ~Testing();
        bool check_if_alive();
        void unalive();
};

Testing::Testing(bool alive, int id) : object_alive{alive}, object_id{id} {
    cout << "\nCONstructor on object: " << object_id << endl;
}
Testing::~Testing(){
    unalive();
    cout << "\nDEstructor on object: " << object_id << endl;
}

bool Testing::check_if_alive(){
    return object_alive;
}

void Testing::unalive(){
    object_alive = false;
    cout << "\nObject " << object_id << " under testing is dying!" << endl;
}

vector<Testing>* gather_objects_under_testing(int amount_of_objects);

int main() {
    vector<Testing>* gas_chamber{gather_objects_under_testing(2)};
    int number_of_objects_alive{0};

    Testing* object_in_front{nullptr};
    object_in_front = &(*gas_chamber).at((gas_chamber->size())-1);

    do{
        number_of_objects_alive = 0;
        object_in_front->unalive();
        object_in_front -= 1;
        for(auto &object: *gas_chamber){
            if(object.check_if_alive())
                ++number_of_objects_alive;
        }
    } while(number_of_objects_alive > 0);

    return 0;
}

vector<Testing>* gather_objects_under_testing(int amount_of_objects){
    vector<Testing>* chamber = new vector<Testing>;
    for(int i{amount_of_objects}; i > 0; --i){
        (*chamber).push_back(Testing(true, i));
    }
    
    return chamber;
}

运行输出

CONstructor on object: 2

Object 2 under testing is dying!

DEstructor on object: 2

CONstructor on object: 1

Object 2 under testing is dying!

DEstructor on object: 2

Object 1 under testing is dying!

DEstructor on object: 1

Object 1 under testing is dying!

Object 2 under testing is dying!

疑问解答与原因分析

1. gather_objects_under_testing中析构多次的原因

多次析构来自两个核心场景:

  • 临时对象销毁:调用push_back(Testing(true, i))时,会先创建一个临时Testing对象(触发构造),将其拷贝到vector内存后,临时对象立即被销毁(触发析构)。
  • vector扩容导致旧元素销毁:vector初始容量为0,第一次push_back会分配1个元素的空间;第二次push_back时,原容量不足,vector会重新分配更大的内存(通常是原容量的2倍),把旧内存中的元素拷贝到新内存,随后销毁旧内存中的元素,再次触发析构。

2. 被销毁的对象具体是哪些

  • 第一次析构:push_back(2)创建的临时对象;
  • 第二次析构:vector扩容时,旧内存中存储的对象2(拷贝到新内存后,旧对象被销毁);
  • 第三次析构:push_back(1)创建的临时对象;
  • 最后两次析构:程序退出时,vector中剩余的两个对象(1和2)被销毁(代码未手动delete vector,属于内存泄漏,但操作系统回收内存前会触发析构)。

3. 为什么感觉修改的是"副本"

你在main中修改的是vector中最终存储的对象,但gather_objects_under_testing过程中,临时对象的unalive调用修改的是临时对象自身的object_alive,和vector中存储的拷贝对象无关——这就是你感知到"修改了未察觉的副本"的原因。

优化方案

方案1:提前预留vector容量

在gather_objects_under_testing中先调用reserve分配足够空间,避免扩容导致的元素拷贝和析构:

vector<Testing>* gather_objects_under_testing(int amount_of_objects){
    vector<Testing>* chamber = new vector<Testing>;
    chamber->reserve(amount_of_objects); // 提前预留容量
    for(int i{amount_of_objects}; i > 0; --i){
        (*chamber).push_back(Testing(true, i));
    }
    
    return chamber;
}

方案2:使用emplace_back替代push_back

emplace_back直接在vector的内存空间中构造对象,无需创建临时对象,彻底避免临时对象的构造和析构:

vector<Testing>* gather_objects_under_testing(int amount_of_objects){
    vector<Testing>* chamber = new vector<Testing>;
    chamber->reserve(amount_of_objects);
    for(int i{amount_of_objects}; i > 0; --i){
        chamber->emplace_back(true, i); // 直接在vector内构造对象
    }
    
    return chamber;
}

方案3:避免裸指针管理vector

代码中new了vector但未delete,会造成内存泄漏。建议直接使用栈上vector或智能指针:

// 改用栈上vector,无需手动管理内存
vector<Testing> gather_objects_under_testing(int amount_of_objects){
    vector<Testing> chamber;
    chamber.reserve(amount_of_objects);
    for(int i{amount_of_objects}; i > 0; --i){
        chamber.emplace_back(true, i);
    }
    return chamber;
}

// main函数调整:
int main() {
    vector<Testing> gas_chamber{gather_objects_under_testing(2)};
    Testing* object_in_front = &gas_chamber.at(gas_chamber.size()-1);
    // 其余代码逻辑不变
}

总结

通过提前预留容量+使用emplace_back,可完全消除不必要的对象构造和析构;同时避免裸指针管理容器,能解决内存泄漏问题,提升代码安全性。

内容的提问来源于stack exchange,提问作者Mikołaj Łajming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:46:02