我被要求优化c ++项目,并且我在类代码中遇到了这种“内存泄漏”情况(示例简化但主要问题很明显):
std::list<T*> _list;
void func(){
T* obj = some_func();
if (!obj){
obj = new T();
_list.push_back(obj); // Here is a leak,we do not know when *obj will be removed from _list to call its destructor
}
obj->some_field = some_value;
}
/*_list will be used and managed somewhere else
and we do not know actually when, where and how.*/
那怎么可以优雅地修复呢?优雅地,我的意思是没有定义我自己的容器。 我需要使用一些智能指针吗?
更新。这不是C ++ 11.所以没有花哨的有用的东西
答案 0 :(得分:3)
那怎么可以优雅地修复呢?
尽可能存储对象,否则存储智能指针。通过哑指针进行内存管理是内存泄漏的一个因素,更糟糕的是。
std::unique_ptr
将是最好的智能指针 - 它匹配单个所有者(列表)的语义,并具有转移和转出所有权的能力。但是,你说过去一直处于困境,所以最好的选择可能是来自TR1或Boost的shared_ptr
。
我是否需要使用一些智能指针?
这是迄今为止最简单的解决方案,假设您无法存储对象。另一种方法是仔细控制如何从列表中删除指针,确保您删除它们或以明确指定的方式转移所有权(并且新所有者正确地履行其职责)。你基本上是定义自己的容器适配器;虽然你可以使用现成的解决方案,比如Boost的指针容器。
答案 1 :(得分:0)
使用some_func的协议是什么?调用者是否应该获得返回对象的所有权?如果是这样,它将被泄露。假设列表取得对象的所有权,您需要将some_func返回的obj推送到列表中。实际上,在这里使用unique_ptrs将有助于使其更加清晰。
答案 2 :(得分:0)
假设您正在存储指向列表(std::list<T*> _list;
)的指针,这可能会有所帮助:
namespace RAII
{
template<typename T>
class AUTO_LIST_WITH_POINTER
{
public:
AUTO_LIST_WITH_POINTER(){}
~AUTO_LIST_WITH_POINTER()
{
// if you compiler does not support lambdas, replace this with
// a simple 'for' loop
std::for_each( list_.begin(), list_.end(), []( T * & listItem )throw()
{
delete listItem;
} );
}
const std::list<T*> & get()const
{
return list_;
}
std::list<T*> & get()
{
return list_;
}
std::list<T*> detach() // Warning: probably an expensive operation!!!!
{
std::list<T*> list( list_ );
list_.clear();
return list;
}
private:
std::list<T*> list_;
AUTO_LIST_WITH_POINTER( const AUTO_LIST_WITH_POINTER & ); // TODO: don't implement, or..?? the OP should know better
AUTO_LIST_WITH_POINTER & operator=( const AUTO_LIST_WITH_POINTER & ); // TODO: don't implement, or..?? the OP should know better
};
}
答案 3 :(得分:0)
其中一个选择是使用RAII,依赖std::unique_ptr
以及移动语义。例如:
std::list<std::unique_ptr<T>> list;
auto obj = some_func();
int some_value = 1;
if (!obj){
std::unique_ptr<T> new_obj(new T());
list.emplace_back(std::move(new_obj));
obj = list.back().get();
}
obj->some_field = some_value;
答案 4 :(得分:0)
如果没有C ++ 11,您可以使用std::auto_ptr<>
。这会将指针的所有权转移给一个所有者,因此如果_list
的类型为std::list<std::auto_ptr<T>>
,则在销毁容器时将删除这些对象。