calling destructor in custom container - c++

I am designing a custom C++ template container like this:
template <class C>
class Container {
public:
...
void clear() {
// should I call destructor on elements here?
for (i...)
array[i].~C(); // ?
}
~Container() {
delete [] array_;
}
private:
C* array_;
};
Should I call the destructor on elements manually inside clear()? If I don't, they will be called later when the container is destroyed (since I delete [] array_ in destructor), but this is not the expected behaviour (we expect them to be destroyed right inside clear(), just like std::vector does).
However, if I do call the destructors, that memory remains in place and when I will be adding new elements on top of the old ones (which now are destroyed), the assignment operator will be called on those destroyed elements, and this may result in undefined behavior.
Suppose I have a class:
class Foo {
public:
Foo() { foo_ = new int; }
~Foo() { delete foo_; } // note I don't explicitly set foo_ to nullptr here
Foo(Foo &&f) {
f.foo_ = std::exchange(foo_, f.foo_); // standard practice in move constructors
}
};
OK, this may look good so far, but now if I make a
Container<Foo> c;
c.add(Foo());
c.clear();
c.add(Foo());
when calling clear() the destructor of the initial Foo is called, leaving its foo_ pointer dangling. Next, when adding the second Foo, the temporary R-value is exchanged with the old contents of the destructed object and when the temp will be destroyed, its destructor will try to delete the same dangling pointer again, which will crash.
So, how to correctly clear() a container without leaving room for double deletion?
I also read that its recommended not to set pointers to nullptr in destructor in order not to not hide potential dangling pointer problems.
I'm a little confused about how to approach this.
EDIT:-------------------
There seems to be no compromise-free approach for a template container.
So far I see these options, as others pointed out:
completely delete the underlying array in clear(); this would be
safe but not performant. I cannot use this option however since I'm
implementing a lock-free multi-threaded container.
instead of calling the destructor on elements in clear(), I would call the default constructor instead: array[i] = C(); This seems
like the best solution so far - except it still implies an extra
default construction.
use placement new in add() - this seems to work for copy-construction. However, move-construction into an uninitialized object still seems problematic because most move constructors are implemented with exchanges between pointers - this would leave the source object (moved from) invalid.

The delete [] array_ will invoke the destructor for each element of array_ (assuming C is a type with a destructor).
Invoking a destructor twice on any given object gives undefined behaviour.
This means your clear() member function should not directly invoke destructors for the array elements.
If you insist on having a separate clear() function, which does not interfere with working of the destructor, simply implement it as
void clear()
{
delete [] array_;
array = nullptr; // NULL or 0 before C++11
}
This won't interfere with the destructor since operator delete has no effect if acting on a NULL pointer.

As you specified in the comments, in the unassigned cells you have objects constructed by the default constructor (T()). That may be bad for performance, but certainly preserves the object abstraction.
Instead of deleting the entries, just replace them with the ones constructed by the default constructor:
template <class C>
class Container {
public:
...
void clear() {
for (i...)
array_[i] = C();
}
~Container() {
delete [] array_;
}
private:
C* array_;
};
Alternative implementation
On the other hand, I would propose a more performant approach, although it breaks the nice C++ abstraction. You could allocate the memory without invoking the unnecessary default constructor:
template <class C>
class Container {
public:
Container(int n) {
array_ = (C*)malloc(sizeof(C)*n);
size_ = 0;
}
...
void clear() {
for (... i < size_ ...)
array_[i].~C();
size_ = 0;
}
~Container() {
clear();
free(array_);
}
private:
C* array_;
int size_;
};
Here you do call destructors on all the initialized elements, but you do not call it second time, because you keep track of which are initialized, which are not.

Related

Is destroying form of operator delete required to actually destroy the object?

C++20 has added destroying form of operator delete distinguished by the std::destroying_delete_t parameter. It causes delete expression to no longer destroy the object prior to invoking operator delete.
The intention is to allow customization of deletion in a way that depends on the object's state, before explicitly invoking the object's destructor and deallocating memory.
However, it isn't clear to me if, when implementing such an operator, I'm actually required to destroy the object. Specifically, am I allowed to have a pool of static objects, and give them out to users who can subsequently treat them as-if they were dynamically allocated? Such that delete expression executed on the object will merely return it to the pool without destroying it. For example, is the following program well-defined?
#include <new>
struct A {
virtual ~A() = default;
};
// 'Regular' dynamically allocated objects
struct B : A {
static A* create() {
return new B();
}
private:
B() = default;
};
// Pooled, statically allocated objects
struct C : A {
static A* create() {
for (auto& c: pool) {
if (!c.in_use) {
c.in_use = true;
return &c;
}
}
throw std::bad_alloc();
}
private:
static C pool[3];
bool in_use = false;
C() = default;
void operator delete(C *c, std::destroying_delete_t) {
c->in_use = false;
}
};
C C::pool[3];
// Delete them identically via the common interface.
void do_something_and_delete(A* a) {
delete a;
}
int main() {
do_something_and_delete(B::create());
do_something_and_delete(B::create());
do_something_and_delete(C::create());
do_something_and_delete(C::create());
}
The purpose of destroying delete operators, as defined by its proposal, is to effectively deal with the ability to create and destroy objects whose deallocation and destruction needs access to the object, for one reason or another. It does this by preventing the automatic invocation of the object's destructor when you invoke delete on objects with a destroying operator delete function. The (still live) object is then passed to the destroying operator delete, so that it can do the deallocation and destruction business.
Its purpose is not to make the statement delete whatever; lie to the user about what this statement accomplishes. But as a consequence of one of the use cases of the feature (virtual destructors without virtual functions), the feature can be (ab)used to lie to the user.
The lifetime of an object ends when its destructor is entered (or when the storage is reused/released). If a destroying operator delete is (ab)used to prevent calling that destructor, then deleteing the object will not end its lifetime.
But lying to the user is a bad idea and you shouldn't do it.

Is it safe to use placement new on 'this' pointer

Current Implementation
I have a class containing unique_ptr fields which depend on one other:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor, then construct a new instance on top
~ResourceManager();
ResourceManager* new_this = new(this) ResourceManager();
// Surely this must be the case, right?
// Is there any reason to prefer using either?
assert(new_this == this);
new_this->b_ptr = that.b_ptr;
new_this->c_ptr = that.c_ptr;
return *new_this;
}
unique_ptr<B> b;
unique_ptr<C> c;
};
Use case
The use case here is that I would like to reassign new values to the pointers, whilst keeping the ResourceManager as a stack-allocated variable, or as a non-pointer class member.
With my current setup I imagine using it something like this:
A a, another_a;
ResourceManager r(&a);
// Use r...
// Destroy old ResourceManager and create the new one in place.
r = ResourceManager(&another_a);
The reason this is even a problem is due to the fact that B and C are non-assignable (for e.g. file streams)
Ugly Alternative
An alternative uglier (and dangerous) method would be to explicitly reset the unique_ptr fields crucially in reverse order (remember that C depends on B, and hence must be destructed first), effectively mimicking the default destruction behaviour.
ResourceManager& operator=(ResourceManager&& that) {
// Mimic destructor call (reverse-order destruction)
c_ptr.reset();
b_ptr.reset();
b_ptr = that.b_ptr;
c_ptr = that.c_ptr;
return *this;
}
Note that a wrong implementation would be to simply use the default assignment operator for ResourceManager. This will assign the field in-order which implies in-order destruction of the unique_ptrs, whereas we require reverse-order destruction.
Questions
Is this usage of this pointer with placement new and the explicit destructor call safe?
Must I use the returned new_this pointer as opposed to the original this pointer (for example, if the this pointer technically becomes invalidated after calling the destructor)?
Are there any better suggested ways to achieve this? If add more such unique_ptr fields to the class, I would have to make sure that I add a copy to the assignment operator. For instance, is it possible to call the move constructor instead, like so:
ResourceManager& operator=(ResourceManager&& that) {
// Call destructor
~ResourceManager();
// Move-construct a new instance on top
ResourceManager* new_this = new(this) ResourceManager(that);
return *new_this;
}
Your solution seems overly complex.
I would code it like this:
class ResourceManager {
ResourceManager() {}
ResourceManager(A* a_ptr) :
b_ptr(new B(a)),
c_ptr(new C(b_ptr.get())) {}
ResourceManager& operator=(ResourceManager&& that)
{
// the order of these moves/assignments is important
// The old value of *(this->c_ptr) will be destroyed before
// the old value of *(this->b_ptr) which is good because *c_ptr presumably
// has an unprotected pointer to *b_ptr.
c_ptr = std::move(that.c_ptr);
b_ptr = std::move(that.b_ptr);
// (a better solution might be to use shared_ptr<B> rather than unique_ptr<B>
return *this;
}
unique_ptr<B> b_ptr;
unique_ptr<C> c_ptr;
};
Note: When the move assignment returns, that will "empty" meaning both that.b_ptr and that.c_ptr are nullptr. This is the expected result of a move assignment.
Or if "reconstructing" the target of the assignment is important (assuming there's extra code not shown in this example that makes it so) I might add a move constructor and a swap method like so:
ResourceManager(ResourceManager&& that)
: b_ptr(std::move(that.b_ptr)),
c_ptr(std::move(that.c_ptr))
{
}
void swap(ResourceManager & that)
{
b_ptr.swap(that.b_ptr);
c_ptr.swap(that.c_ptr);
}
ResourceManager& operator=(ResourceManager&& that)
{
ResourceManager temp(std::move(that));
this->swap(temp);
return *this;
}

Field variable deleted before actual destructor called?

What would make a field variable become obsolete before entering the destructor upon deletion of the object?
I was a looking for an answer for this problem I'm having on this site and came across this:
Lifetime of object is over before destructor is called?
Something doesn't add up at all: if I've declared a pointer to SomeClass inside another WrapperClass, when I construct the WrapperClass I need to create a new SomeClass and delete it on destruction of the wrapper.
That makes sense and has worked so far.
The pointer is still valid and correct well into the destructor otherwise obviously I wouldn't be able to delete it.
Now my problem is that my field members (both an int and a pointer to a SomeClass array) of WrapperClass are garbage when I call the destructor. I've checked the wrapper object just after construction and the data is fine. The wrapper is actually a pointer in another Main class and the problem occurs when I destruct that Main (which destructs the wrapper) but works fine if I just delete the wrapper from another method in Main.
My paranoia led me to the above mentioned answer and now I'm totally confused.
Anybody care to shed some light on what's really going on here?
EDIT:
Node is the SomeClass.
class WrapperException{};
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
Node** nodes;
public:
Wrapper() : numNodes(0) { nodes = new Node*[SIZE]; }
Wrapper(const Wrapper& other) { throw WrapperException(); }
Wrapper& operator=(const Wrapper& other) { throw WrapperException(); }
~Wrapper() { //calling delete Main gets me here with garbage for numNodes and nodes
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete nodes;
}
};
class MainException{};
class Main {
public:
Main() { wrapper = new Wrapper(); }
Main(const Main& other) { throw MainException(); }
Main& operator=(const Main& other) { throw MainException(); }
~Main() { delete wrapper; }
private:
Wrapper* wrapper;
};
You need to use the Standard library to implement this behaviour.
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
std::vector<std::unique_ptr<Node>> nodes;
public:
Wrapper() : numNodes(0) { nodes.resize(SIZE); }
// No explicit destructor required
// Correct copy semantics also implemented automatically
};
class Main {
public:
Main() : wrapper(new Wrapper()) {}
// Again, no explicit destructor required
// Copying banned for move-only class, so compiler tells you
// if you try to copy it when you can't.
private:
std::unique_ptr<Wrapper> wrapper;
};
This code is guaranteed to execute correctly. When in C++, if you have used new[], delete or delete[], then immediately refactor your code to remove them, and review three times any use of non-placement new- constructing a unique_ptr is pretty much the only valid case. This is nothing but a common, expected outcome of manual memory management.
Since Grizzly isn't answering, I'll put this out there.
Both your Main class and your Wrapper class need properly implemented copy constructors and assignment operators. See The Rule of 3.
The problem is, if your class ever gets copied(which is easy to happen without you even realizing it), then the pointers get copied. Now you've got two objects pointing to the same place. When one of them goes out of scope, it's destructor gets called, which calls delete on that pointer, and the pointed to object gets destroyed. Then the other object is left with a dangling pointer. When it gets destroyed, it tries to call delete again on that pointer.
The lifetime of your wrapper object has ended, but the integer and pointer sub-objects as well as the pointee are still alive. When you invoke delete on the pointer, the pointee's lifetime ends, but the pointer still remains alive. The pointer's lifetime ends after your dtor is complete.
Thus, if your members have become corrupted, there is something else afoot.
Node** nodes;
should be
Node * nodes;
Also the destructor is wrong. It should be:
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete [] nodes;
There might be other problems as well as e.g. you haven't created a copy constructor or assignment operator so that might make it so that the copy of an object then deletes the object for you.
EDIT: changed the destructor...

Copy data from a pointer or chain of pointers (Object pointer, templates)

How the push_back of stl::vector is implemented so it can make copy of any datatype .. may be pointer, double pointer and so on ...
I'm implementing a template class having a function push_back almost similar to vector. Within this method a copy of argument should be inserted in internal allocated memory.
In case the argument is a pointer or a chain of pointers (an object pointer); the copy should be made of actual data pointed. [updated as per comment]
Can you pls tell how to create copy from pointer. so that if i delete the pointer in caller still the copy exists in my template class?
Code base is as follows:
template<typename T>
class Vector
{
public:
void push_back(const T& val_in)
{
T a (val_in); // It copies pointer, NOT data.
m_pData[SIZE++] = a;
}
}
Caller:
// Initialize my custom Vector class.
Vector<MyClass*> v(3);
MyClass* a = new MyClass();
a->a = 0;
a->b = .5;
// push MyClass object pointer
// now push_back method should create a copy of data
// pointed by 'a' and insert it to internal allocated memory.
// 'a' can be a chain of pointers also.
// how to achieve this functionality?
v.push_back(a);
delete a;
I can simply use STL vector to accomplish the tasks but for experiment purposes i'm writing a template class which does exactly the same.
Thanks.
if you have polymorphic object ( the pointed object may be more specialized than the variable ), I suggest you creating a virtual method called clone() that allocate a new pointer with a copy of your object:
Base* A::clone() {
A* toReturn = new A();
//copy stuff
return toReturn;
}
If you can't modify your Base class, you can use RTTI, but I will not approach this solution in this answer. ( If you want more details in this solution, please make a question regarding polymorphic cloning with RTTI).
If you have not a polymorphic object, you may allocate a new object by calling the copy constructor.
void YourVector::push_back(Base* obj) {
Base* copy = new Base(obj);
}
But it smells that what you are really needing is shared_ptr, avaliable in <tr1/memory> ( or <memory> if you use C++0x ).
Update based on comments
You may also have a two template parameters list:
template <typename T>
struct CopyConstructorCloner {
T* operator()(const T& t) {
return new T(t);
}
}
template <typename T, typename CLONER=CopyConstructorCloner<T> >
class MyList {
CLONER cloneObj;
public:
// ...
void push_back(const T& t) {
T* newElement = cloneObj(t);
// save newElemenet somewhere, dont forget to delete it later
}
}
With this approach it is possible to define new cloning politics for things like pointers.
Still, I recommend you to use shared_ptrs.
I think for this kind of problems it is better to use smart pointers ex: boost::shared_ptr or any other equivalent implementation.
There is no need to call new for the given datatype T. The push_back implementation should (must) call the copy-constructor or the assignment operator. The memory should have been allocated to hold those elemnets that are being pushed. The intial memory allocation should not call CTOR of type T. Something like:
T* pArray;
pArray = (T*) new BYTE[sizeof(T) * INITIAL_SIZE);
And then just put new object into pArray, calling the assignment operator.
One solution is to make a copy construction:
MyClass *p = new MyClass();
MyVector<MyClass*> v;
v.push_back(new MyClass(*p));
Update: From you updated question, you can definitely override push_back
template<typename T>
class MyVector {
public:
void push_back (T obj); // general push_back
template<typename TYPE> // T can already be a pointer, so declare TYPE again
void push_back (TYPE *pFrom)
{
TYPE *pNew = new TYPE(*pFrom);
// use pNew in your logic...
}
};
Something like this:
template<typename T>
class MyVector
{
T* data; // Pointer to internal memory
size_t count; // Number of items of T stored in data
size_t allocated; // Total space that is available in data
// (available space is => allocated - count)
void push_back(std::auto_ptr<T> item) // Use auto pointer to indicate transfer of ownership
/*void push_back(T* item) The dangerous version of the interface */
{
if ((allocated - count) == 0)
{ reallocateSomeMemory();
}
T* dest = &data[count]; // location to store item
new (dest) T(*item); // Use placement new and copy constructor.
++count;
}
// All the other stuff you will need.
};
Edit based on comments:
To call it you need to do this:
MyVector<Plop> data;
std::auto_ptr<Plop> item(new Plop()); // ALWAYS put dynamically allocated objects
// into a smart pointer. Not doing this is bad
// practice.
data.push_back(item);
I use auto_ptr because RAW pointers are bad (ie in real C++ code (unlike C) you rarely see pointers, they are hidden inside smart pointers).

Safe placement new & explicit destructor call

This is an example of my codes:
template <typename T> struct MyStruct {
T object;
}
template <typename T> class MyClass {
MyStruct<T>* structPool;
size_t structCount;
MyClass(size_t count) {
this->structCount = count;
this->structPool = new MyStruct<T>[count];
for( size_t i=0 ; i<count ; i++ ) {
//placement new to call constructor
new (&this->structPool[i].object) T();
}
}
~MyClass() {
for( size_t i=0 ; i<this->structCount ; i++ ) {
//explicit destructor call
this->structPool[i].object.~T();
}
delete[] this->structPool;
}
}
My question is, is this a safe way to do? Do I make some hidden mistake at some condition? Will it work for every type of object (POD and non-POD)?
No, because both your constructor and destructor are invoked twice. Because you have this:
template <typename T> struct MyStruct {
T object;
}
When you construct a MyStruct<T> the compile will construct the inner T and when you delete the object the inner T will have the destructor called automatically.
For this example, there is no need for placement new or an explicit destructor call.
Placement new would be useful if you allocate raw memory. For example, if you changed your new to:
this->structPool = new char[sizeof(T) * count];
then you would want to placement new and explict destructor call.
No, it is certainly not even remotely safe way to do it. When you do new MyStruct<T>[count] for non-POD T, each MyStruct<T> object in the array already gets default-constructed, meaning that the constructor for the object member gets called automatically. Then you attempt to perform an in-place construction (by value-initialization) on top of that. The resultant behavior is undefined.
The same problem exists with the deletion.
What is it you are trying to achieve? Just do new MyStruct<T>[count]() (note the extra empty ()) and it will already perform value-initialization for each element of the array (exactly what you are trying to do "manually" afterwards). Why do you feel you have to do it by in-place construction?
Likewise, when you do
delete[] this->structPool;
it automatically calls the destructor for each MyStruct<T>::object member in the array. No need to do it manually.
Remembering new will always call the constructor, no matter if it is placement or not.
-- So your code used new twice. This will call the constructor twice. If you want to avoid this, either:
Change your first new into malloc(or any kind of alloc)
Remove your second placement new
To delete the objects in an array, the best way is: Invoke every object's destructor; free the memory.
-- So you can do either:
Delete the object with delete[] if you are using new[]
Call every destructor and do a C style free if you are using malloc and placement new
template <typename T> class MyClass {
void* structPool;
size_t structCount;
MyClass(size_t count)
: structPool(new char[sizeof(T)*count], structCount(count)
{
//placement new to call constructor
for( size_t i=0 ; i<count ; i++ )
new (structPool+i*sizeof(T)) T();
}
~MyClass() {
//explicit destructor call
for( size_t i=0 ; i<structCount ; i++ )
reinterpret_cast<T*>(structPool+i*sizeof(T))->~T();
delete[] structPool;
}
}
Note that this isn't exception-safe: If one of the constructors causes an exception, it doesn't call the destructors on the objects already constructed and it leaks the memory. When one of the destructors throws, this fails, too.
Have a look at std::vector in your favorite std lib implementation in order to see how to do this right. However, that leads to the question: Why do you want to do this in the first place?
A std::vector already does all this, does it right, you can use it out of the box, and everyone looking at your code will understand it immediately:
template <typename T> class MyClass {
std::vector<T> data_;
MyClass(size_t count) : data() {data.resize(count);}
//~MyClass() not needed
}