Safe placement new & explicit destructor call - c++

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
}

Related

unsafe template array constructor

This is probably a simple question but I have this template class:
template<typename Type>
class Array {
size_t n;
Type* buff;
public:
Array(size_t n_): n(n_), buff(new Type[n]) {}
};
The code is from a course pdf file where it says buff(new Type[n]) is unsafe. I don't understand why it's unsafe, isn't size_t generally unsigned? Can I have an example where it could have a compile and/or run-time error?
The code is "unsafe" in the fact that it relies on n being constructed before buff. This dependency adds brittleness to the code.
When you construct the members of the class they are constructed in the order the are declared in the class, not how they are called in the member initialization list, so if the code was changed to
template<typename Type>
class Array {
Type* buff;
size_t n;
public:
Array(size_t n_): n(n_), buff(new Type[n]) {}
};
Then when you do buff(new Type[n]), n is uninitialized and you have undefined behavior.
First of all the order, the initializations for the constructor are executed is not determined by the order they are written down, but by the order the initialized fields appear in the code:
class Array {
size_t n;
Type* buff;
public:
Array(size_t n_): n(n_), buff(new Type[n]) {}
};
Here first n will be initialized and then buff.
class Array {
Type* buff;
size_t n;
public:
Array(size_t n_): n(n_), buff(new Type[n]) {}
};
Now first buff will be initialized and then n, so n has no defined value in that case.
Using initialization lists for constructors is good practice, but be careful, that you don't create any assumptions on the order.
Generally it is a good idea to refrain from owning raw pointers. If you use smart pointers instead, you can not forget to release the data.
In the specific case, you might also want to use std::vector instead of a C-style array. That handles all the allocation, reallocation, releases, etc. in a thread safe manner for you. It seems like you are trying to write something like your own std::vector. Please only do that for educational purposes. Always prefer the standard implementation in production code. You probably won't get it better for quite a while. If you did, you would ask different questions here ;-)
First of all, you have a memory leak. But the question probably isn't about that. So let's assume you have a destructor that deallocates the array.
template<typename Type>
class Array {
size_t n;
Type* buff;
public:
Array(size_t n_): n(n_), buff(new Type[n]) {}
~Array() { delete[] buff; }
};
Now this particular code is perfectly safe. No exception can be thrown while assigning n_, the order of initialization is correct and buff is the only raw pointer in your class. However, as you start expanding your class and writing more classes, the risk of a memory leak increases.
Imagine that you need to add one more members to the class Array:
template<typename Type>
class Array {
size_t n;
Type* buff;
SomethingElse xyz;
public:
Array(size_t n_): n(n_), buff(new Type[n_]), xyz(n_) {}
~Array() { delete[] buff; }
};
If the constructor of SomethingElse throws, the memory allocated for buff will leak, because the destructor ~Array() will never be called.
Modern C++ calls pointers such as Type* buff raw pointers because you are responsible for deallocating storage yourself (taking exceptions into account), and introduces tools such as std::unique_ptr and std::shared_ptr that can take care of storage deallocation automatically.
In modern C++ you could write your class like this:
template<typename Type>
class Array {
size_t n;
std::unique_ptr<Type[]> buff;
public:
Array(size_t n_): n(n_), buff(new Type[n_]) {}
};
Notice the absence of a destructor. The unique_ptr will take care of calling delete for you.
Note also no dependency on class members inside the initializer list (simply writing new Type[n_] instead of new Type[n] makes your code more robust)
C++98 Standard 12.6.2.5.4 (I don't expect new versions to have relaxed this).
— Then, nonstatic data members shall be initialized in the order they
were declared in the class definition (again regardless of the order
of the mem-initializers).
So the order of initialization is defined according to this.
If you want an example of how to crash it simply make sizeof(Type)*n > total memory in your system.
It is not safe to call new operator inside initialization list.
if new fails the destructor of Array will not be called.
here is a similar question.
Are there any issues with allocating memory within constructor initialization lists?

calling destructor in custom container

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.

C++ Is constructing object twice using placement new undefined behaviour?

I have come across some code which has horrified me.
Essentially it follows this pattern :
class Foo
{
public:
//default constructor
Foo(): x(0), ptr(nullptr)
{
//do nothing
}
//more interesting constructor
Foo( FooInitialiser& init): x(0), ptr(nullptr)
{
x = init.getX();
ptr = new int;
}
~Foo()
{
delete ptr;
}
private:
int x;
int* ptr;
};
void someFunction( FooInitialiser initialiser )
{
int numFoos = MAGIC_NUMBER;
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
//... do stuff
delete[] fooArray;
}
This code has been in the code base for years and it would seem has never caused a problem. It's obviously a bad idea since someone could change the default constructor to allocate not expecting the second construction. Simply replacing the second constructor with an equivalent initialisation method would seem the sensible thing to do. eg.
void Foo::initialise(FooInitialiser& init)
{
x = init.getX();
ptr = new int;
}
Although still subject to possible resource leaks, at least a defensive programmer might think to check for prior allocations in a normal method.
My question is:
Is constructing twice like this actually undefined behaviour/ outlawed by standard or simply just a bad idea? If undefined behaviour can you quote or point me to right place to look in the standard?
Generally, working with placement new in this way is not a good idea. Calling an initializer from the first new, or calling an initializer instead of placement new are both considered to be better form than the code you've provided.
However, in this case, the behaviour of calling placement new over an existing object is well defined.
A program may end the lifetime of any object by reusing the storage
which the object occupies or by explicitly calling the destructor for
an object of a class type with a non-trivial destructor. For an object
of a class type with a non-trivial destructor, the program is not
required to call the destructor explicitly before the storage which
the object occupies is reused or released; however, if there is no
explicit call to the destructor or if a delete-expression (5.3.5) is
not used to release the storage, the destructor shall not be
implicitly called and any program that depends on the side effects
produced by the destructor has undefined behavior.
So when this happens:
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
The placement new operation will end the lifetime of the Foo that was there, and create a new one in it's place. In many circumstances this could be bad, but given the way your destructor works, this will be fine.
Calling placement new on an existing object could be undefined behaviour, but it depends on the specific object.
This does not produce undefined behaviour, because you are not depending on the "side effects" produced by the destructor.
The only "side-effect" in the destructor of your object is to delete the contained int pointer, but in this case that object is never in a deletable state when placement new is called.
If it was possible for the contained int pointer to be equal to something other than nullptr and could possibly require deleting, then calling placement new over the existing object would invoke undefined behaviour.

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).