如果我有以下代码,
Foo *f = new Foo();
vector<Foo*> vect;
vect.push_back(f);
// do stuff
vect.erase(f);
我是否造成了内存泄漏?我猜是这样,但擦除这个词给人的感觉是它正在删除它。
写到这里,我想知道将指针放在 STL 向量中是否是一个错误。你怎么看?
是的,您由此造成了内存泄漏。std::vector 和其他容器只会删除指针,它们不会释放指针指向的内存。
将指针放入标准库容器中并不罕见。但是,问题是您必须在将其从容器中删除时跟踪删除它。一种更好但更简单的方法是使用 boost::shared_ptr:
{
boost::shared_ptr<foo> f(new foo);
std::vector< boost::shared_ptr<foo> > v;
v.push_back(f);
v.erase(v.begin());
} /* if the last copy of foo goes out of scope, the memory is automatically freed */
下一个 C++ 标准(通常称为 C++1x 和 C++0x)将包括std::shared_ptr
. 在那里,您还可以使用std::unique_ptr<T>
更快的,因为它不允许复制。在 c++0x 中使用std::unique_ptr
容器类似于ptr_container
boost 中的库。
另一种选择是使用 Boost Pointer Containers。它们旨在完全按照您的意愿行事。
或者有 boost::ptr_vector容器。
它知道它持有它拥有的指针,因此会自动删除它们。
作为一个很好的副作用,当访问元素时,它返回对对象的引用而不是指针,以使代码看起来不错。
Foo *f = new Foo();
boost::ptr_vector<Foo> vect;
vect.push_back(f);
// do stuff
vect.erase(f);
为了澄清为什么不删除指针,请考虑
std::vector<char const*> strings;
strings.push_back("hello");
strings.push_back("world");
// .erase should not call delete, pointers are to literals
std::vector<int*> arrays;
strings.push_back(new int[10]);
strings.push_back(new int[20]);
// .erase should call delete[] instead of delete
std::vector<unsigned char*> raw;
strings.push_back(malloc(1000));
strings.push_back(malloc(2000));
// .erase should call free() instead of delete
一般来说,vector<T*>::erase
无法猜测您将如何处理T*
.
将指针指向标准容器绝对不是错误(但是,创建 auto_ptr 的容器是错误的)。是的,您确实需要显式删除以释放各个元素指向的内存,或者您可以使用 boost smart pointers之一。
vector 删除它包含的数据。由于您的向量包含指针,它只删除指针,而不是它们可能指向或可能不指向的数据。
在 C++ 中,内存在分配的地方释放是一个非常普遍的规则。向量没有分配你的指针指向的任何东西,所以它不能释放它。
您可能首先不应该将指针存储在向量中。在许多情况下,您最好使用以下方法:
vector<Foo> vect;
vect.push_back(Foo());
// do stuff
vect.erase(f);
当然这假设 Foo 是可复制的,并且它的复制构造函数不是太昂贵,但是它避免了内存泄漏,并且您不必记住删除 Foo 对象。另一种方法是使用智能指针(例如 Boost 的 shared_ptr),但您可能根本不需要指针语义,在这种情况下,简单的解决方案是最好的解决方案。
STL 容器不会释放您的内存。最好的建议是使用智能指针,因为它知道 std::auto_ptr 不适合容器。我会推荐 boost::shared_ptr,或者如果您的编译器供应商支持 TR1 扩展(很多都支持),您可以使用 std::tr1::shared_ptr。
另请注意,向量甚至不会释放为指针保留的内部存储器。即使调用 clear(),std::vectors 也不会缩小大小。如果您需要缩小矢量,您将不得不求助于创建另一个矢量并交换内容。