Does Std::List::Remove Method Call Destructor of Each Removed Element

Does std::list::remove method call destructor of each removed element?

Yes, removing a Foo* from a container destroys the Foo*, but it will not release the Foo. Destroying a raw pointer is always a no-op. It cannot be any other way! Let me give you several reasons why.

Storage class

Deleting a pointer only makes sense if the pointee was actually allocated dynamically, but how could the runtime possibly know whether that is the case when the pointer variable is destroyed? Pointers can also point to static and automatic variables, and deleting one of those yields undefined behavior.

{
Foo x;
Foo* p = &x;

Foo* q = new Foo;

// Has *q been allocated dynamically?
// (The answer is YES, but the runtime doesn't know that.)

// Has *p been allocated dynamically?
// (The answer is NO, but the runtime doesn't know that.)
}

Dangling pointers

There is no way to figure out whether the pointee has already been released in the past. Deleting the same pointer twice yields undefined behavior. (It becomes a dangling pointer after the first delete.)

{
Foo* p = new Foo;

Foo* q = p;

// Has *q already been released?
// (The answer is NO, but the runtime doesn't know that.)

// (...suppose that pointees WOULD be automatically released...)

// Has *p already been released?
// (The answer WOULD now be YES, but the runtime doesn't know that.)
}

Uninitialized pointers

It is also impossible to detect whether a pointer variable has been initialized at all. Guess what happens when you try to delete such a pointer? Once again, the answer is undefined behavior.

    {
Foo* p;

// Has p been properly initialized?
// (The answer is NO, but the runtime doesn't know that.)
}

Dynamic arrays

The type system does not distinguish between a pointer to a single object (Foo*) and a pointer to the first element of an array of objects (also Foo*). When a pointer variable is destroyed, the runtime cannot possibly figure out whether to release the pointee via delete or via delete[]. Releasing via the wrong form invokes undefined behavior.

{
Foo* p = new Foo;

Foo* q = new Foo[100];

// What should I do, delete q or delete[] q?
// (The answer is delete[] q, but the runtime doesn't know that.)

// What should I do, delete p or delete[] p?
// (The answer is delete p, but the runtime doesn't know that.)
}

Summary

Since the runtime cannot do anything sensible with the pointee, destroying a pointer variable is always a no-op. Doing nothing is definitely better than causing undefined behavior due to an uninformed guess :-)

Advice

Instead of raw pointers, consider using smart pointers as the value type of your container, because they take responsibility for releasing the pointee when it is no longer needed. Depending on your need, use std::shared_ptr<Foo> or std::unique_ptr<Foo> . If your compiler does not support C++0x yet, use boost::shared_ptr<Foo>.

Never, I repeat, NEVER EVER use std::auto_ptr<Foo> as the value type of a container.

Does std::list's erase member function call the destructor for all stored elements?

When you call the clear() method of the list, it will destroy all of the objects stored inside of the list. In your case, you have a list of demo*s This means that each of the pointers will be destroyed, since the pointers are stored inside the list, but the pointees won't be destroyed because the pointees aren't stored inside the list. In other words, destroying the pointers isn't the same as calling delete on each of those pointers. As a result, it's usually not recommended to store raw pointers in container types if those pointers own the objects they point at, since, as you've just seen, the destructors aren't called automatically.

Now, on the other hand, suppose you have a list<unique_ptr<demo>>. In that case, calling clear() will destroy all the unique_ptr<demo>s in the list. This in turn will deallocate the objects that the unique_ptrs point at, since destroying a unique_ptr also destroys the object it points at. This works because unique_ptr has an idea of ownership and realizes that it needs to destroy the object it points at when it is itself destroyed.

Hope this helps!

Does std::remove_if call the destructor?

std::remove_if does not move elements to be removed to the end. Instead, it moves elements not to be removed to the front; the contents of the tail are left unspecified.

In the process, some elements that the predicate says should be removed may be overwritten by (to be precise, assigned from) other elements. For an element that's a shared_ptr, this means it may very well destroy the underlying object.

What you seem to be looking for is std::partition. It behaves exactly the way you seem to expect std::remove_if to behave.

Does delete[] call destructors?

If T has a destructor then it will be invoked by delete[]. From section 5.3.5 Delete of the c++11 standard (draft n3337), clause 6:

If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will
invoke the destructor (if any) for the object or the elements of the array being deleted
. In the case of an
array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion
of their constructor; see 12.6.2).

The destructor for a type T will also be invoked for each element in an array of T[] when the array is not dynamically allocated and array goes out of scope (lifetime ends).


I need to know this, because the objects in my class do not contain sensible values all the time, so the destructors should not be called when they don't.

But, there seems to be a very significant problem with an object that can acquire a state where it cannot be destructed.

C++ Clearing std::list of structs in class destructor

As to the need for list::clear() see the other answers. I should add that if the destructor of ABC has no other explicit jobs to do, you may just omit it and the compiler will automatically generate it for you.

As to the way to populate the list. You want to avoid deep copies of large data. This can be achieved by moving

std::list<ABC> list;
ABC big(data_needed_for_constructing_ABC);
list.push_back(std::move(big));

provided class ABC has an efficient move constructor (which may be automatic if it's memory management uses standard functionality such as std::vector or std::unique_ptr).

You may also construct the new list element directly into the list

std::list<ABC> list;
list.emplace_back(data_needed_for_constructing_ABC);

when no temporary object ABC big ever exists.

Finally, if you cannot move the object efficiently and you want to have another copy of the object somewhere else, you may consider std::list<std::shared_ptr<ABC>>. However, that is only sensible if there is no clear ownership.

Is destructor called when removing element from STL container?

No.

When you remove a pointer from a container, all you've done is take that pointer value from the container, nothing is deleted. (i.e.: pointers have no destructor.)

However, it's dangerous to have pointers of things in containers. Consider:

std::vector<int*> v;
v.push_back(new int());
v.push_back(new int());
v.push_back(new int());

If you never go through the container and delete each one, you've leaked. Worse is it's not exception safe. You should use a pointer container, which will delete things it points to when they are erased. (And all get erased when the container destructs.)

In your case, though, since you are sharing a pointer in different places, I can't see an argument against shared_ptr; that's exactly what it was made for.

Does std::vector.clear() do delete (free memory) on each element?

No (you need to do the delete yourself at the end as you suggest in your example as the destruction of the bald pointer doesnt do anything). But you can use a boost [or other RAII-based idiom] smart pointer to make it Do The Right Thing (auto_ptr would not work correctly in a container as it has incompatible behaviour under copying etc.), but be sure you understand the pitfalls of such smart pointers before use. (As Benoit mentions, in this case, basic_string is what you're really looking for here.)

Having said that there's a need to understand the pitfalls of smart pointers, having them take care of the memory management implicitly so you dont have to do it explicitly is far less error-prone.

EDIT: Substantially revised to encompass the elements Benoit brought into his far more thorough answer, thanks to strong prodding from the Earwicker and James Matta - thanks for pushing me to do the due diligence on this!

C++ Destructors with Vectors, Pointers,

std::vector and std::strings: Are they destroyed automatically?

Yes (assuming member variables are not pointers to std::vector and std::string).

If I have something like std::vector what happens when the vector destructor is called?
Would it call automatically the destructor of myClass? Or only the vector is destroyed but all the Objects it contains are still existant in the memory?

If vector<MyClass> then all objects contained in the vector will be destroyed. If vector<MyClass*> then all objects must be explicitly deleted (assuming the class being destructed owns the objects in the vector). A third alternative is vector of smart pointers, like vector<shared_ptr<MyClass>>, in which case the elements of the vector do not need to be explictly deleted.

What happens if I have a pointer to another class inside a class

The B must be explicitly deleted. Again, a smart pointer could be used to handle the destruction of B.



Related Topics



Leave a reply



Submit