Reputation: 23
I want to destroy the templated object, but keep the allocated memory to be filled. Unfortunately, the destructor of the object is never called, and stepping through the code, it skips the manual call.
#include <iostream>
template <typename type> class TestClass
{
private:
type *data;
public:
TestClass();
~TestClass();
template <typename T> void Set(T &&element);
void Replace();
};
template <typename type> TestClass<type>::TestClass()
{
data = reinterpret_cast<type *>(new char[sizeof(type)]);;
}
template <typename type> TestClass<type>::~TestClass()
{
}
template <typename type> template <typename T> void TestClass<type>::Set(T &&element)
{
new(data) type(static_cast<T &&>(element));
}
template <typename type> void TestClass<type>::Replace()
{
type *pointer = reinterpret_cast<type *>(&data[0]);
pointer->~type();
//Fill with data
}
class MyClass
{
public:
MyClass()
{
}
~MyClass()
{
std::cout << "Called" << "\n";
}
};
int main()
{
MyClass *myClass = new MyClass();
TestClass<MyClass *> myObject;
myObject.Set(myClass);
myObject.Replace();
return 0;
}
I have tested this in VS 2017 and on an online C++ compiler. Both skip the pointer->~type(); when stepping through and the destructor is never called.
Edit: Rewrote code which now reproduces the error.
Upvotes: 0
Views: 60
Reputation: 72291
To allow templates to deal generally with types, C++ allows a obj.~type()
or ptr->~type()
syntax even when the type is not a class type (but not for an array type). The meaning is the same as whatever would happen to an automatic object of that type at the end of its scope: if it is a class type, the destructor is called, and if not, nothing happens. For the case when the type is not a class type, this syntax is called a pseudo-destructor.
Now looking at your example, you're using the class template specialization TestClass<MyClass*>
. So in the instantiation of the member definition for TestClass<type>::Replace()
, type
is an alias for MyClass*
. The statement
type *pointer = reinterpret_cast<type *>(&data[0]);
defines a variable of type type*
, which is MyClass**
. (The right-hand side is confusing: &data[0]
is the same as data
assuming it points at something, and both expressions already have type type*
.)
The statement
pointer->~type();
says to destroy the object of type type
which pointer
points at. That is, it says to destroy the object of type MyClass*
which is *pointer
. MyClass*
is not a class type; it is a pointer type. So this is a call to a pseudo-destructor, and absolutely nothing happens.
There's not enough context to say for certain how this would be fixed, but perhaps you need to use TestClass<MyClass>
instead of TestClass<MyClass*>
? (Also, in real code don't forget the Rule Of Five/Rule Of Three.)
Upvotes: 0
Reputation: 162
It does call destructor.
#include <iostream>
class Type
{
public:
~Type()
{
std::cout<< __FUNCTION__ << "\n";
}
};
template <typename type> class MyClass
{
private:
type *data;
public:
MyClass();
~MyClass(){}
void Replace();
};
template <typename type> MyClass<type>::MyClass()
{
data = reinterpret_cast<type *>(new char[sizeof(type)]);;
}
template <typename type> void MyClass<type>::Replace()
{
type *pointer = &data[0];
pointer->~type();
//Fill with replacement data
}
int main()
{
MyClass<Type> myClass;
std::cout <<"Before destruction\n";
myClass.Replace();
std::cout << "After destruction\n";
return 0;
}
Upvotes: 1