我对如何做到这一点的最佳做法感到有些困惑。假设我有一个类,例如分配一些内存。我希望它像汽车一样自我毁灭,但也因为某种原因将其放在矢量中。
#include <iostream>
#include <vector>
class Test {
public:
Test();
Test(int a);
virtual ~Test();
int counter;
Test * otherTest;
};
volatile int count = 0;
Test::Test(int a) {
count++;
counter = count;
std::cout << counter << "Got constructed!\n";
otherTest = new Test();
otherTest->counter = 999;
}
Test::Test() {
count++;
counter = count;
std::cout << counter << "Alloced got constructed!\n";
otherTest = NULL;
}
Test::~Test() {
if(otherTest != 0){
std::cout << otherTest->counter << " 1Got destructed" << counter << "\n";
otherTest->counter = 888;
std::cout << otherTest->counter << " 2Got destructed" << counter << "\n";
}
}
int vectorTest(){
Test a(5);
std::vector<Test> vecTest;
vecTest.push_back(a);
return 1;
}
int main(){
std::cout << "HELLO WORLD\n";
vectorTest();
std::cout << "Prog finished\n";
}
在这种情况下,我的析构函数从计数器1中被调用两次,alloc'对象已经被设置为888(或者在实际情况下被释放导致对已删除对象的错误访问)。将局部变量放入向量的正确情况是什么,这是一种永远不会发生的设计。以下行为有所不同,析构函数只调用一次(考虑到它的分配是有意义的。)
int vectorTest(){
//Test a(5);
std::vector<Test> vecTest;
vecTest.push_back(*(new Test(5)));
return 1;
}
如何使局部变量的行为相同,导致只对析构函数进行一次调用?一个地方根本不会被放在一个向量中吗?但是不是向量优先于数组的向量,如果有一些本地对象需要单独初始化并放入向量并将其传递给另一个函数而不使用空闲/堆内存,该怎么办?我想我在这里缺少一些至关重要的东西。这是某种转移所有权的智能指针的情况吗?
答案 0 :(得分:9)
向量维护自己的存储并将值复制到其中。由于您没有实现复制构造函数,因此使用默认复制构造函数,它只复制指针的值。因此,该指针被删除两次,一次由局部变量析构函数删除,一次由向量删除。不要忘记rule of three。您需要实现复制和赋值运算符,或者只使用已经执行此操作的类,例如shared_ptr。
请注意,此行会导致内存泄漏,因为您使用new分配的对象永远不会被删除:
vecTest.push_back(*(new Test(5)));
答案 1 :(得分:1)
除了Dark Falcon所写的内容:为了避免在插入向量时重新分配,通常会实现一个交换函数来将局部元素与向量中的默认构造交换。交换只会交换指针的所有权,一切都会很好。新的c ++ 0x也有通过rvalue-references的move-semantics来帮助解决这个问题。
答案 2 :(得分:1)
很可能,你最好让你的向量保持指向Test对象而不是Test对象本身的指针。对于在堆上分配内存的对象(如此测试对象)尤其如此。如果你最终在向量上使用任何算法(例如std :: sort),算法将不断分配和释放内存(这会大大减慢它的速度)。