这不是一个实际问题,但它只是为了教育好奇心。
在某些论坛中,我刚刚发现了这段代码:
std::vector<MyClass*> myvec;
for(unsigned int i = 0; i < 100; ++i) {
myvec.push_back(new MyClass( foo1 ));
}
// somewhere in the code inside a particular if statement
MyClass* replacement = new MyClass( foo2 );
delete myvec[0];
myvec[0] = replacement;
我有一个MyClass实例的向量,代码中的某处我必须用其他实例替换某些实例。
为什么我要拨打删除?更换指针不够吗?
答案 0 :(得分:5)
如果你没有delete
原始的MyClass
,那么它将保持不变,但是因为你擦掉了它的指针,它将无法访问。那是memory leak。
请注意,如果初始分配中的任何new
表达式(第一个除外)抛出,那么您将泄漏先前分配的元素。
所有这一切都可以通过不使用vector
指针而不是简单的std::vector<MyClass>
,或者如果你真的需要使用智能指针来避免。
答案 1 :(得分:2)
您需要明确释放内存,否则它将保持分配状态,但无法访问。这不是Java或C#,垃圾收集器会处理它。
答案 2 :(得分:2)
C ++中最大的问题之一是存储在对象矢量中的类型。
如果对象是可默认构造,可复制和可分配的,则可以存储实例向量,但如果复制和分配很昂贵,那么可以将它们存储在向量中。此外,如果您检索要修改的值,则需要检索引用。但是,如果在您持有此引用时向量发生更改,则您的引用可能会失效
您可以存储指针向量。然后你需要管理指针的生命周期,因为向量不会。
您可以存储shared_ptr
的向量,这通常是完成的。它并不理想,因为对象的所有权可能在向量中。你不会遇到麻烦,但这不是处理大量物品的最完美方式。
boost为指针提供了一个特殊的向量,可以为您管理生命周期。可以是一个很好的选择
新的C ++ 11将允许可移动对象的向量,我认为也可以允许unique_ptr的向量(auto_ptr的向量不是)。
这是相当主观的,但理想的是将typedef指定为指针类型,然后使用该typedef的向量。如果适合您,您可以稍后更改typedef。 shared_ptr
可能会为你完成这项工作。
现在最终结果如下:
typedef spns::shared_ptr< MyClass > MyClassPtr;
// spns is an alias to the namespace you use for shared_ptr, either std or boost
std::vector<MyClassPtr> myvec;
for(unsigned int i = 0; i < 100; ++i)
{
myvec.push_back(MyClassPtr( new MyClass( foo1 ));
// but with C++11 if you still use shared_ptr replace with
// myvec.push_back( spns::make_shared<MyClass>(foo1) );
}
// somewhere in the code inside a particular if statement
MyClass* replacement = new MyClass( foo2 );
myvec[0] = MyClassPtr( replacement );
// preferred alternative to above 2 lines
// myvec[0].reset( new MyClass(foo2) );
答案 3 :(得分:1)
std::vector<MyClass*>
是一个指针向量。它不管理它所拥有的对象的生命周期 - 它只管理它所代表的指针数组的内存。
如果您没有正确管理delete
,则最终会出现泄漏(除非您最终从另一个错误中删除两次)。
答案 4 :(得分:1)
指针的标准容器永远不会删除它包含的任何指针的目标。它无法知道它们指向使用new
创建的对象 - 它们可能是使用new[]
创建的(在这种情况下需要delete[]
),或者它们可能是指向静态的指针或自动对象,不得删除,或者可能还有其他东西负责删除它们。
通常,您将对象存储在容器中,而不是指针中。如果你真的需要指针(可能是因为对象需要是不同的类型),并且你真的需要这些指针来管理对象的生命周期,可以考虑使用智能指针,例如std::unique_ptr
,它会自动删除它的目标,或{ {1}}如果没有。
否则,如果你真的必须使用原始指针来管理对象的生命周期,那么你必须小心谨慎地在适当的时候使用boost::ptr_vector
。在这种情况下,诸如Valgrind之类的工具可以帮助识别不可避免的内存泄漏。
答案 5 :(得分:1)
致电时
new MyClass( foo1 )
内存在堆中分配,用于存储类MyClass的对象。 此记忆保持分配状态,直到您使用删除自己释放它。
因此,对于每次调用new,您应该在代码中的某处删除相应的调用。
答案 6 :(得分:0)
在你的vector
中,你存储了指针,指向你自己的内存。如果你刚刚替换了vector的一个元素,那么该向量对该内存没有任何作用,也许某些类会自动释放该内存,但vector不会这样做。我认为你可以在正常数组中考虑相同的条件而不是向量。