Mastering with new / delete

Using malloc and free , you can easily select structures with additional data outside. But how can I do the same with new / delete ?

I know that I could use the new allocation syntax along with malloc for the selection part, but will delete work correctly and portable if I put the object in the memory allocated by malloc ?

What I want to do is the same as in the following example, but using new / delete instead of malloc / free , so that the constructors / destructors will be called properly:

 #include <cstdlib> #include <cstring> #include <iostream> class Hamburger { int tastyness; public: char *GetMeat(); }; char *Hamburger::GetMeat() { return reinterpret_cast<char *>(this) + sizeof(Hamburger); } int main(int argc, char* argv[]) { Hamburger* hb; // Allocate a Hamburger with 4 extra bytes to store a string. hb = reinterpret_cast<Hamburger*>(malloc(sizeof(Hamburger) + 4)); strcpy(hb->GetMeat(), "yum"); std::cout << "hamburger is " << hb->GetMeat() << std::endl; free(hb); } 

Exit: hamburger is yum

+8
c ++ memory-management new-operator
source share
5 answers

If I were you, I would use the placement new and explicitly call the destructor instead of delete .

 template< typename D, typename T > D *get_aux_storage( T *x ) { return reinterpret_cast< D * >( x + 1 ); } int main() { char const *hamburger_identity = "yum"; void *hamburger_room = malloc( sizeof( Hamburger ) + strlen( hamburger_identity ) + 1 ); Hamburger *hamburger = new( hamburger_room ) Hamburger; strcpy( get_aux_storage< char >( hamburger ), hamburger_identity ); cout << get_aux_storage< char const >( hamburger ) << '\n'; hamburger->~Hamburger(); // explicit destructor call free( hamburger_room ); } 

Of course, this kind of optimization should only be done after profiling has proven the need. (Do you really save the memory this way? Will it be harder to debug?)

There can be no significant technical difference, but new and delete tell me that the object is created and destroyed, even if the object is just a symbol. When you allocate an array of characters as a common “block”, it uses an array allocator (especially suitable for arrays) and conditionally builds characters in it. Then you should use the new placement to create a new object on top of these characters, which is essentially a smoothing of the objects or a double construction, and then double destruction when you want to delete everything.

It is better to bypass the C ++ object model using malloc / free than to twist it to avoid processing data as objects.

Oh, an alternative is to use a custom operator new , but it might be a worm bank, so I don't recommend it.

 struct Hamburger { int tastyness; public: char *GetMeat(); static void *operator new( size_t size_of_bread, size_t size_of_meat ) { return malloc( size_of_bread + size_of_meat ); } static void operator delete( void *ptr ) { free( ptr ); } }; int main() { char const *hamburger_identity = "yum"; size_t meat_size = strlen( hamburger_identity ) + 1; Hamburger *hamburger = new( meat_size ) Hamburger; strcpy( hamburger->GetMeat(), hamburger_identity ); cout << hamburger->GetMeat() << '\n'; } 
+2
source share

You can do this without resorting to malloc / free or undefined (I'm not sure about reinterpret_cast, but at least building / demolishing can be done just fine).

To allocate memory, you can simply call the global new operator directly. After that you use the good old placement of the new to create the object. You should guard the ctor-call, though, since the "delete location" function that caused the ctor error does not free up memory, it just does nothing (just like a new location does nothing).

To destroy an object after this, you can (and can) call the destructor directly and free up memory, which you can call with the global delete operator.

I think that it should also be okay to just delete it, like any ordinary object, since calling the handle and the global operator after the removal will be exactly what will be performed by normal removal, but I'm not 100% sure.

Your example has changed as follows:

 #include <cstdlib> #include <cstring> #include <iostream> class Hamburger { int tastyness; public: char *GetMeat(); }; char *Hamburger::GetMeat() { return reinterpret_cast<char *>(this) + sizeof(Hamburger); } int main(int argc, char* argv[]) { Hamburger* hb; // Allocate space for a Hamburger with 4 extra bytes to store a string. void* space = operator new(sizeof(Hamburger) + 4); // Construct the burger in that space hb = new (space) Hamburger; // TODO: guard ctor call (release memory if ctor fails) strcpy(hb->GetMeat(), "yum"); // OK to call member function on burger now std::cout << "hamburger is " << hb->GetMeat() << std::endl; // To delete we have to do 2 things // 1) call the destructor hb->~Hamburger(); // 2) deallocate the space operator delete(hb); } 
+3
source share

Urgh. Well, let's see. You definitely cannot highlight with new / malloc and delete with free / remote. You must use the appropriate pairs.

I suppose you could use "hp = new char [sizeof (Hamburger) + 4]" and "delete [] ((char *) hp)" as well as explicit constructor / destructor calls if you really wanted to do this.

The only reason I can think of why you want to do this is because you didn't have a Hamburger source, i.e. it was a library class. Otherwise, you would just add a member to it! Can you explain why you want to use this idea?

+2
source share

There is another way you could come close to this if you have a fairly limited set of fill amounts. You can create a template class with a fill amount as a template parameter, and then create it using a set of possible fill amounts. So, if, for example, you knew that you only need 16, 32, or 64 bytes, you can do this as follows:

 template <int Pad> class Hamburger { int tastiness; char padding[Pad]; }; template class Hamburger<16>; template class Hamburger<32>; template class Hamburger<64>; 
0
source share

Is there a reason why a simple, easy, and safe way is not applicable?

 class Hamburger { public: void Extend( const std::string& pExtension) { mContent += pExtension; } const std::string& GetMeat() ... private: std::string mContent; }; int main() { Hamburger hb; hb.Extend("yum"); std::cout << "hamburger is " << hb.GetMeat() << std::endl; } 
0
source share

All Articles