在STL容器中释放内存

时间:2016-05-01 14:43:01

标签: c++ memory-management lambda iterator

我有一个对象列表:

struct reply_t {
    unsigned int xid;
    char *buf;     
};

std::list<reply_t> > replies;

我想删除该列表中的一些元素(xid <= confirmed_id)。我喜欢std :: remove_if提供的简洁。

remove_if(replies.begin(), replies.end(), 
   [&confirmed_id](const reply_t &arg) { return arg.xid <= confirmed_id; }); 

问题是这不会释放buf(在其他地方分配)。有没有一种优雅的方式来处理这个?它是否像在对象析构函数中添加free(buf)一样简单?

4 个答案:

答案 0 :(得分:5)

你可以为reply_t实现一个删除buf的析构函数:

struct reply_t {
    unsigned int xid;
    char *buf;
    ~reply_t() { delete buf; }
};

答案 1 :(得分:2)

这段代码是C和C ++的邪恶沙拉。

在C ++中,每个类都应该有一个构造函数来累积对象所需的东西,析构函数释放对象在其生命周期中获得的任何资源。

您提供的结构是一个纯C结构,它不与C ++容器一起使用,也不与C ++语言哲学一起使用。它不能清理&#34;垃圾&#34;它会产生泄漏。

使用C ++语言调用的构造函数 - accumulates-Destructor-releases RAII 成语。

你的对象应该有一个合适的构造函数和析构函数:

Listview

答案 2 :(得分:2)

正如其他人所说,是的,您可以添加析构函数来执行删除操作。他们遗漏的是,当你这样做时,你必须实现一个复制构造函数和赋值运算符。否则,当您将其中一个对象复制到列表中时,复制的对象将删除缓冲区,然后该对象的副本也将删除缓冲区。这是个坏消息。或者,如同建议的那样,使用std::string代替char*;这样,编译器生成的拷贝构造函数和赋值运算符就会做正确的事。

答案 3 :(得分:0)

The signature does not need to have const &, but the function must not modify the objects passed to it.

Here is a possible implementation of remove_if

template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}

所以也许您可以通过此代码实现,但是您应该通过为您的类添加析构函数或使用std :: string而不是char *来实现它。

remove_if(replies.begin(), replies.end(), 
[&confirmed_id](reply_t &arg) 
{ 
    if(arg.xid <= confirmed_id)  
    {
        delete[] arg.buf;
        arg.buf = nullptr;
        return true;
    }
    return false;
});