简体   繁体   中英

memory freeing in STL containers

I have a list of objects:

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

std::list<reply_t> > replies;

I would like to remove some elements of that list (those such that xid <= confirmed_id ). I like the conciseness provided by std :: remove_if .

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

The problem is that this doesn't free the buf s (that are allocated somewhere else). Is there an elegant way to deal with this? is it as simple as adding free(buf) in the object destructor?

you can implement a destructor for reply_t that deletes buf:

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

This code is an evil salad of C and C++.

in C++, every class should have a constructor that accumulates what the object needs, and a destructor which releases any resource the object had acquired in its life-time.

the struct you have provided is a pure C struct, it doesn't go along with the C++ containers nor with the C++ language philosophy. it cannot clean the "garbage" it produced and therfore leaks.

the Constructor-accumulates-Destructor-releases called in the C++ language the RAII idiom.

your object should have a proper constructor and destructor:

struct reply_t {
    unsigned int xid;
    char *buf;     

   reply_t() xid(0),buf(nullptr){}
   ~reply_t() {  delete buf; }
};

As others have said, yes, you can add a destructor to do the delete. What they've left out is that when you do that you must also implement a copy constructor and an assignment operator. Otherwise, when you copy one of these objects into the list, the object that was copied will delete the buffer, and then later the copy of that object will also delete the buffer. That's bad news. Or, as has also been suggested, use std::string instead of a char* ; that way, the compiler-generated copy constructor and assignment operator will do the right thing.

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;
}

So maybe you can implement by this code, but you should implement it by adding a destructor for your class or using std::string instead of 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;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM