Explicit Construction/Destruction

Started by
13 comments, last by Enigma 18 years, 11 months ago
Hiya folks, I've got another question for your worthy minds to solve which evades me [smile] Anyway, I'm roughing out a memory manager right now, and I just realized that I have no idea at all how one would go about calling the constructor and destructor of an object without actually freeing the memory. Let's imagine I have a StrongPointer class, templated. It has a void pointer to some allocated memory as a member, and I want to be able to call the constructor and destructor of the template type on that memory at will, such as when it has no more references, or whatever. Note that this is not a good example really, and it does not really reflect on what I'm actually doing, it's simply there to possibly help explain what my explanation bungled [smile] I found out how to use placement new, and that should be relatively easy to use with templates, but the methods I saw of calling the destructors without de-allocting the memory seem to be ill-suited to use with templates. Annnyway, if anyone could point out to me how I would do this, I'd much appreciate it.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Advertisement
  void * someMemory = malloc( sizeof( TheClass ) );  // construction  obj = new( someMemory ) TheClass( constructor arguments );  // destruction  obj->~TheClass();  // "someMemory" should be separately freed  free( someMemory );

enum Bool { True, False, FileNotFound };
But Hplus, what if the type of class is a template argument? Can I then simply call:
TheObject->~T();
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Yes, but I still don't see why calling the destructor manually is usefull... It gets called on the call to delete/free anyway.

Toolmaker

A C++ variation on hplus0603's code:

  void * someMemory = ::operator new( sizeof( TheClass ) );  // construction  obj = new( someMemory ) TheClass( constructor arguments );  // destruction  obj->~TheClass();  // "someMemory" should be separately freed  ::operator delete( someMemory);


Toolmaker - A C++ vector allocates memory and constructs elements separately. It will allocate more memory than needed to allow for growth, and constructs the new elements in the preexisting memory as it goes. And in reverse, will destroy the elements without deallocating the memory, until the vector itself gets destroyed.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Just to clarify, the free call will not call the destructor automatically as Toolmaker said. In most situations when using placement new you will need to manually call the destructor.
The operator new allocates the needed memory, and then calls the contructor. The operator delete calls the destructor then frees the memory.

If you did use malloc (or some other memory allocation method), you would need to call the constructors and destructors of classes explicitly. In C++, unless you are using your own memory management system, you should be using new, new[], delete, and delete[] to allocate and deallocate memory.

Often the constructors and destructors are called directly in the case of using memory pooling (even then there is a form of new that can be used to to point at a spefic memory allocation). Something like this would be used if you used malloc to allocate a giant heap of memory to be used. You wouldn't want to call delete on something that was created in that pool of memory, since you don't actually want to release the memory completely from memory, you just want to make it avaiable, do you would explicitly call the destructor to safely destroy the object. (Note: This is basically another topic all together).

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

Quote:Original post by Rattrap
The operator new allocates the needed memory, and then calls the contructor. The operator delete calls the destructor then frees the memory.

Nearly, but actually the new operator allocates memory (via operator new) and then calls the constructor. The delete operator calls the destructor and then frees the memory (via operator delete). There is a difference between the new operator and operator new (and equivalently for delete). The latter deals in uninitialised memory and can be overloaded. The former deals in initialised objects and cannot be overloaded.

Enigma
I'm sorry, was I not very clear or something? I'm fully cognizant that new/delete call the constructor and destructor, and I know that malloc/free do not. I cannot use new and delete, because I'm working on a memory manager, which doesn't allow just deleting chunks of memory in the middle of a heap. Thus I need to be able to call the destructor of an object of an unknown type without freeing the memory, thus effectively deleting dead objects, which keeping the memory for later usage.

The key words there are of an unknown type, thus, I cannot explicitly call the destructor like so many people told me to do, that is:
foo->~MyClass();
Because, the type of object being a template argument, what happens when the object type is not a MyClas, but a Bar, or something else?
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Toolmaker already answered your question. Yes, you can use the template argument as the destructor name:
#include <iostream>#include <new>#include <string>class Test1{	public:		Test1()			:			a(7),			b('z'),			c(3.14f)		{			std::cout << "Test1 constructor\n";		}		~Test1()		{			std::cout << "Test1 destructor\n";		}		void print() const		{			std::cout << "Test1\n\t" << a << "\n\t" << b << "\n\t" << c << '\n';		}	private:		int a;		char b;		float c;};class Test2{	public:		Test2()			:			a(7),			b(new char('F')),			c("This is a string")		{			std::cout << "Test2 constructor\n";		}		~Test2()		{			std::cout << "Test2 destructor\n";		}		void print() const		{			std::cout << "Test2\n\t" << a << "\n\t" << *b << "\n\t" << c << '\n';		}	private:		int a;		char * b;		std::string c;};template < typename TYPE >class Wrapper{	public:		Wrapper()			:			object_(static_cast< TYPE * >(::operator new(sizeof(TYPE))))		{		}		~Wrapper()		{			::operator delete(object_);		}		void allocate()		{			new (object_) TYPE();		}		void release()		{			object_->~TYPE();		}		TYPE const * operator->() const		{			return object_;		}	private:		TYPE * object_;};int main(){	Wrapper< Test1 > wrapperOne;	Wrapper< Test2 > wrapperTwo;	wrapperTwo.allocate();	wrapperOne.allocate();	wrapperOne->print();	wrapperTwo->print();	wrapperOne.release();	wrapperTwo.release();	wrapperOne.allocate();	wrapperOne->print();	wrapperOne.release();}

Enigma

This topic is closed to new replies.

Advertisement