STL容器中的内存释放

memory freeing in STL containers

本文关键字:内存 释放 STL      更新时间:2023-10-16

我有一个对象列表:

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)一样简单?

您可以为reply_t实现一个析构函数,用于删除buf:

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

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

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

您提供的结构是一个纯C结构,它既不符合C++容器,也不符合C++语言哲学。它无法清除它产生的"垃圾",从而导致泄漏。

构造函数累积在C++语言中调用的Destructor释放,即RAII习惯用法。

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

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

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

签名不需要有常量&,但是函数不能修改传递给它的对象。

以下是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;
});