C ++对象被摧毁了不止一次

时间:2014-04-11 20:11:11

标签: c++ constructor destructor instantiation raii

当编写一些将(部分)数据结构加载到图形内存中的代码时,我对这种意外行为感到惊讶。

我已将代码简化为以下内容:

#include <iostream>
#include <vector>
using namespace std;

struct Data{
    int data;
    Data(int x){
        data = x;
        cout<<"+ Data"<<endl;
    }
    ~Data(){cout<<"- Data"<<endl;}
};

struct Handle{
    // imagine some handles to video memory here
    Handle(Data d){
        // (upload data to video memory)
        cout<<"+ Handle"<<endl;
    }
    ~Handle(){
        // (deallocate the data from video memory)
        cout<<"- Handle"<<endl;
    }
};

int main(){
    vector<Handle> container;
    cout<<"start"<<endl;
    for(int i=0; i<4; i++){
        container.emplace_back(Data(i));
        cout<<endl;
    }
    cout<<"end"<<endl;
}

我的期望:

start
+ Data
+ Handle
- Data

+ Data
+ Handle
- Data

+ Data
+ Handle
- Data

+ Data
+ Handle
- Data

end
-Handle
-Handle
-Handle
-Handle

我得到了什么:

start
+ Data
+ Handle
- Data
- Data

+ Data
+ Handle
- Data
- Handle
- Data

+ Data
+ Handle
- Data
- Handle
- Handle
- Data

+ Data
+ Handle
- Data
- Data

end
- Handle
- Handle
- Handle
- Handle

任何人都可以解释这种行为吗?

2 个答案:

答案 0 :(得分:4)

Handle(Data d)按值获取Data个对象,因此Handle构造函数中的d实际上是传递给Handle构造函数的对象的副本。由于必须创建副本,因此必须销毁副本。它的范围是Handle构造函数的主体,这就是为什么它发生在&#34; + Handle&#34;

之后

这里的构造函数应该是什么样的:

Handle(const Data& d){
    // (upload data to video memory)
    cout<<"+ Handle"<<endl;
}

const引用是为了防止不必要的复制。

答案 1 :(得分:4)

您对代码的修改可以帮助您更好地了解正在发生的事情。

#include <iostream>
#include <vector>
using namespace std;

struct Data{
    int data;
    static int allcount;
    int count;
    Data(int x) : count(allcount) {
        data = x;
        allcount++;
        cout<<"+ Data "<< count <<endl;
    }
    Data(const Data &d) : count(allcount) {
        allcount++;
        cout<<"+ Data(copy of " << d.count << ") "<< count <<endl;
    }
    ~Data(){cout<<"- Data "<< count <<endl;}
};

struct Handle{
    static int allcount;
    int count;
    // imagine some handles to video memory here
    Handle(Data d) : count(allcount) {
        allcount++;
        // (upload data to video memory)
        cout<<"+ Handle " << count << endl;
    }
    Handle(const Handle &h) : count(allcount) {
        allcount++;
        cout<<"+ Handle(copy of " << h.count << ") "<< count <<endl;
    }
    ~Handle(){
        // (deallocate the data from video memory)
        cout<<"- Handle " << count <<endl;
    }
};

int Handle::allcount=0;
int Data::allcount=0;

int main(){
    vector<Handle> container;
    cout<<"start"<<endl;
    for(int i=0; i<4; i++){
        container.emplace_back(Data(i));
        cout<<endl;
    }
    cout<<"end"<<endl;
}

它的作用是用一个整数跟踪每个分配和释放,以唯一地标识每个分配和释放。还明确添加了复制构造函数。当我在我的系统上运行时,我得到以下内容:

start
+ Data 0
+ Data(copy of 0) 1
+ Handle 0
- Data 1
- Data 0

+ Data 2
+ Data(copy of 2) 3
+ Handle 1
- Data 3
+ Handle(copy of 0) 2
- Handle 0
- Data 2

+ Data 4
+ Data(copy of 4) 5
+ Handle 3
- Data 5
+ Handle(copy of 2) 4
+ Handle(copy of 1) 5
- Handle 2
- Handle 1
- Data 4

+ Data 6
+ Data(copy of 6) 7
+ Handle 6
- Data 7
- Data 6

end
- Handle 4
- Handle 5
- Handle 3
- Handle 6

如您所见,Handle被多次复制。这是因为当他们调入的容器调整大小时需要复制它们。如果添加行

container.reserve(4);

就在打印&#34;开始&#34;的行之前,我想你会在第一时间看到你期望看到的内容。也就是说,没有Handle个副本。