在我的C ++代码中,我有一个类Object,它配有int类型的id字段。现在我想创建一个Object *类型的指针向量。首先我试过
vector<Object*> v;
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
但这失败了,因为这里同一地址只重复了n次。如果我使用new运算符,我会得到我想要的但我想避免动态内存分配。然后我认为我需要的是以某种方式在for循环之前声明n个不同的指针。直截了当的方法是声明一个数组,所以我这样做了:
vector<Object*> v;
Object ar[n];
for(int i=0; i<n; i++) {
ar[i] = Object(i);
}
for(int i=0; i<n; i++) {
v.push_back(ar+i);
}
如果我这样做,是否还有可能导致内存泄漏?在我看来,通过数组声明也有点笨拙。有没有其他方法来创建指针向量但避免手动内存管理?
编辑:为什么我需要指针而不仅仅是普通对象?
嗯,我稍微修改了原来的实际情况,因为我以这种方式思考,我可以用最简单的形式表示问题。无论如何,我仍然认为这个问题可以在不知道为什么我需要一个指针向量的情况下得到解答。
其实我有
Class A {
protected:
vector<Superobject*> vec;
...
};
Class B: public A {...};
Class Superobject {
protected:
int id;
...
}
Class Object: public Superobject {...}
在派生类B
中,我想用vec
类型的对象填充成员字段Object
。如果超类没有使用指针,我会遇到对象切片问题。因此,在类B
构造函数中,我想将vec
初始化为类型Object*
的指针向量。
EDIT2
是的,在我看来,动态分配是合理的选择,使用数组的想法是个坏主意。当数组超出范围时,事情就会出错,因为向量中的指针指向不一定包含对象的内存位置。
在B类的构造函数中我有
B(int n) {
vector<Object*> vec;
Object ar[n];
for(int id=0; id<n; id++) {
ar[id] = Object(id);
}
for(int id=0; id<n; id++) {
v.push_back(ar+id);
}
}
这导致了B类对象中非常奇怪的行为。
答案 0 :(得分:8)
在这个循环中:
for(int id=0; id<n; id++) {
Object ob = Object(id);
v.push_back(&ob);
}
您正在堆栈上创建n次Object实例。在每次迭代时都会创建并删除元素。你可以使用它来避免这种情况:
for(int id=0; id<n; id++) {
Object* ob = new Object(id);
v.push_back(ob);
}
感谢每个新元素都存在于不在堆栈上的堆上。尝试在类构造函数中添加类似的东西:
std::cout<<"Object ctor()\n";
和析构函数中的相同:
std::cout<<"Object dtor()\n";
如果您不想使用@woolstar
编写的“新”尝试原因创建这些对象答案 1 :(得分:5)
关于内存泄漏的问题让我觉得你担心这些对象的生命周期和清理。我最初提出了shared_ptr
包装器,但是C ++ 11给了我们unique_ptr
,而C ++ 14填充了缺少的make_unique
。尽我们所能:
vector<unique_ptr<SuperObject>> v ;
您使用完美转发和可变参数模板的精彩创建,
v.push_back( make_unique<Object>( ... ) ) ;
是的,您将不得不忍受一些堆分配,但是当v
消失时,所有内容都将被清除。
有人提出了一个提升库ptr_container
,但这不仅需要为您的项目添加提升功能,还需要教育所有未来的读者ptr_container
是什么和做什么。
答案 2 :(得分:3)
您的版本中没有内存泄漏。当程序离开你的范围时,矢量和数组也会被销毁。关于第二个问题:为什么不直接将对象直接存储在矢量中?
vector<Object> v;
for(int i = 0; i < n; i++)
{
Object obj = Object(i);
v.push_back(obj);
}