Archived

This topic is now archived and is closed to further replies.

null_pointer

What is the proper syntax for invoking placement delete?

Recommended Posts

Sorry for asking such a simple question, but Visual C++ .NET 2002 always seems to invoke the standard delete instead of the placement delete, and this causes debug assertions in the standard library. What is the proper syntax for invoking placement delete? I have tried the following:
  
delete (address) object;
delete (address, object);
  
The former will not compile. The Visual C++ documentation shows the latter syntax in an example program, but the compiler translates this into a call to the non-placement delete. Is this a bug in the compiler?

Share this post


Link to post
Share on other sites
$18.4.1.3 (7-10):

quote:
  void operator delete(void* ptr, void*) throw(); 


7 Effects: Intentionally performs no action.
8 Notes: Default function called when any part of the initialization in a placement new expression that
invokes the library’s nonarray
placement operator new terminates by throwing an exception (5.3.4).

  void operator delete[](void* ptr, void*) throw(); 


9 Effects: Intentionally performs no action.
10 Notes: Default function called when any part of the initialization in a placement new expression that
invokes the library’s array placement operator new terminates by throwing an exception (5.3.4).

Share this post


Link to post
Share on other sites
quote:
Whats wrong with delete Object;


The standard operators new and delete allocate and deallocate the memory and invoke the constuctor and destructor whereas the standard operators *placement* new and delete just invoke the constructor and destructor on memory that has already been allocated. This is useful in writing a custom memory manager, among other things.

Share this post


Link to post
Share on other sites
quote:
Original post by null_pointer
Yes, there is. Find it in the standard.

"placement delete" does not occur anywhere in the Standard.
quote:

$18.4.1.3 (7-10):

Where does that say "placement delete"?

If you want to destroy an object allocated using placement new, then you call the dtor for the object, and then perform clean-up according to whatever your custom allocation schema demands.
quote:
Original post by RhoneRanger
OK I get it!

No you don''t. You''ve entirely missed the point.

Share this post


Link to post
Share on other sites
quote:
Original post by null_pointer
Yes, there is. Find it in the standard.



"placement delete" only gets called if the constructor called from placement new throws an exception. Otherwise, call the destructor and operator delete manually.

MSN

Share this post


Link to post
Share on other sites
The problem is that C++ provides no other way to explicitly invoke a constructor. Let''s say you wanted to write your own implementation of std::vector. Without placement new and delete, how would you reserve memory without actually constructing objects in it? And then when you needed to resize the vector, how would you construct objects in the reserved memory? For these things you would need to use placement new to indirectly invoke the constructor.

Share this post


Link to post
Share on other sites
quote:
"placement delete" does not occur anywhere in the Standard.
...
Where does that say "placement delete"?


Why are you bothering me about a search string? You do know how to open the table of contents and look up the section entitled memory allocation, right?

quote:
If you want to destroy an object allocated using placement new, then you call the dtor for the object, and then perform clean-up according to whatever your custom allocation schema demands.


That is how I normally do it.

quote:
"placement delete" only gets called if the constructor called from placement new throws an exception.


That is not what the standard says. Strike the word "only."

quote:
Otherwise, call the destructor and operator delete manually.


No, "placement delete" is merely another overload of delete and can be called like any other overload of delete:


  
// An overload that uses a garbage collector.

 
class GC {};
 
void* operator new (size_t, GC&) { return 0; }
void operator delete (void*, GC&) {}
 
// A standard do-nothing overload a.k.a. placement new and delete.

 
void* operator new (size_t, void*) {}
void operator delete (void*, void*) {}
 
int main ()
{
// Invoke the overload using the garbage collector.

 
GC gc;
int* int_pointer = new (gc) int (5);
delete (gc, int_pointer);
 
// Invoke the standard do-nothing overload a.k.a. placement new and delete.

 
char memory [sizeof int];
int* int_pointer = new (memory) int;
delete (memory, int_pointer); // VC barfs!

}


Since no one seems willing to help, I installed Dev-C++ 4.8.0 and tested it myself. This works as I expected:


  
#include <new>
 
int main()
{
char memory [4];
int* int_pointer = new (memory) int (5);
delete (memory, int_pointer);
}


One can even open the header file "new" and use the debugger to step into the empty "placement delete" operator definition.

EDIT: Fixed example code and removed some unncessary and irritating comments.

[edited by - null_pointer on April 28, 2003 10:11:33 AM]

Share this post


Link to post
Share on other sites
Hmm...upon further testing of my code, it seems that neither Visual C++ .NET 2002 nor Dev-C++ 4.8.0 will actually call *any* overloads of operator delete except for the following standard overload:


  
# include <new>
 
int main ()
{
int* int_pointer = new (nothrow) int (5);
delete (nothrow, int_pointer);
}


So why does the compiler not call any overload of operator delete except for nothrow?

quote:
I already answered your question.


No, you simply said that there is no "placement delete" even though the standard defines it as a standard overload of operator delete. I should be able to call it just as well as any user-defined overload of operator delete. In fact, they do not even allow me to call any user-defined overloads of operator delete even though they compile without any errors! I ask you, does that make any sense?

Share this post


Link to post
Share on other sites
*rant mode*

Looking at TC++PL and the standard again, it seems that the "delete (nothrow, object)" syntax is a Visual C++-ism. Why both GCC 3.2 and Visual C++ .NET 2002 support the same little extension is beyond me.

Even more frustrating is trying to understand why there is such a half-baked overloading mechanism in the standard. The authors of the standard have graciously provided an overloading mechanism for operator new so that one can encapsulate calls to custom memory manager allocation routines behind a nice, predictable interface:


  
void* operator new (size_t size, custom_memory_manager& manager)
{
return manager.allocate (size);
}

int main ()
{
small_object_manager manager;
object* pointer_to_object = new (manager) object;
}


But can you overload operator delete? Yes. Can you call it? No, certainly not. Well, that is, you may call it by using a ridiculously obfuscated syntax:


  
void* operator new (size_t size, custom_memory_manager& manager)
{
return manager.allocate (size);
}

void operator delete (void* memory, custom_memory_manager& manager)
{
manager.deallocate (memory);
}

int main ()
{
small_object_manager manager;
object* pointer_to_object = new (manager) object;
pointer_to_object->~object ();
operator delete (pointer_to_object, manager);
}


So what the heck happened to overloading delete? Did they just take an unfortunately timed lunch break and forget to put that part in the standard when they went back to work? Why couldn''t they just allow one to do the following?


  
int main ()
{
small_object_manager manager;
object* pointer_to_object - new (manager) object;
delete (manager, object);
// -or-

delete (manager) object;
}


Why?

Share this post


Link to post
Share on other sites
quote:
Really?


No. I was positive that if I created a custom overload of operator delete, I would be able to invoke it using the same nice, neat syntax that one expects from operator new. Sadly, the standardization committee did not provide the corresponding rules for delete. VC++ and Dev-C++ both support the syntax in question but compile it to something entirely different from what I have intended. That is, one can compile and run the following example in both implementations without any errors even though it is not Standard C++.


  
// An overload that uses a garbage collector.


class GC {};

void* operator new (size_t, GC&) { return 0; }
void operator delete (void*, GC&) {}

int main ()
{
// Invoke the overload using the garbage collector.


GC gc;

int* int_pointer = new (gc) int (5);
delete (gc, int_pointer); // calls 'void operator delete (void*)'

}


The only reason Visual C++ does not give a debug assertion when it calls the standard delete instead of the user-defined overload of delete is that the user-defined overload returns a null pointer.

[edited by - null_pointer on April 28, 2003 1:42:38 PM]

Share this post


Link to post
Share on other sites
Yes, there _IS_ such thing as placement delete, and as msn12b said, you do not call it explicity, rather it gets called when placement new fails (throws an exception). Only placment delete will be called when placement new fails, the ''normal'' delete will not be called.

the C++ standard lib even includes an implementation of placement delete with void*. just crack open you header file and take a peak.

Share this post


Link to post
Share on other sites
The new and delete operators assume you''re going to be using standard C++ memory management, which is not the case here. You really ought to make some kind of persistent memory-management object...something like:



const int hunksize = 1024; //hunksize = 1k

struct alloc{
int location;
size_t size;
void * ptr;
};

class MemManage{
void * hunk;
int sz = 1024 / sizeof(int);
MemManage(){ hunk = new int[sz]; }
vector< alloc > allocations;
void * new(size_t size){
//check through allocations and find a suitable spot
//enter the size and location into allocations
//return a pointer
}
void delete(){
//search through allocations and knock off the right one, then zero the memory if you wish
}
};



But this is all very sloppy. There''s really no reason to write your own memory manager if you have access to C++''s. If you need high-performance in certain areas why don''t you just organize your data better?

Share this post


Link to post
Share on other sites
quote:

There''s really no reason to write your own memory manager if you have access to C++''s.


Yes there is. For very small objects, the C++ memory manager is very slow. Loki''s small object allocator is much, much faster.

And as for why you can''t call "placement" operator delete:
http://cpptips.hyperformix.com/cpptips/placement_del

Share this post


Link to post
Share on other sites
quote:
The new and delete operators assume you're going to be using standard C++ memory management, which is not the case here.


No, that is false. Even Stroustrop gives an example of overloading new to implement a custom memory manager in TC++PL page 256. The problem is that the standard does not allow one to have the same nice syntax with operator delete, as you can see in this example that I created:


    
class MemoryManager
{
void* allocate (size_t);
void deallocate (void*);
 
friend void* operator new (size_t size, MemoryManager& MM)
{ return MM.allocate (size); }
 
friend void operator delete (void* memory, MemoryManager& MM)
{ return MM.deallocate (memory); }
};
 
int main ()
{
// Create a memory manager.

 
MemoryManager MM;
 
// Use the memory manager to allocate a new int with a value of 5.

 
int* p = new (MM) int (5);
 
// Destruct the integer. Note how relatively poor the syntax is

// when compared to constructing an integer.

 
p->~int ();
operator delete (p, MM);
}


The syntax should be like this to match:


  
delete (MM) p;


Surely you can see how much simpler that would be?

quote:
You really ought to make some kind of persistent memory-management object...something like:


When you add new and delete to a class as members, they are used to allocate instances of that class and not other classes. Also, you must use the operator keyword when defining them because they are operators.

quote:
There's really no reason to write your own memory manager if you have access to C++'s.


I can think of a few valid reasons. What if I want to learn? What if I want to gather my own set of memory usage statistics about my program? What if I need quick allocations of small objects and the implementation's memory manager has too much overhead?

quote:
If you need high-performance in certain areas why don't you just organize your data better?


What if I prefer to express things the way they are even if that means writing a custom memory manager? Or to put it another way, must I really contort my design to make all of it work well with a single generic-purpose memory allocator?

quote:
And as for why you can't call "placement" operator delete:


Most of the discussion just centered around whether the compiler could be able to automatically call user-defined overloads of delete, a feature which would require some very undesirable run-time overhead. The only reason given there for not having a placement delete expression to match the placement new expression is that the syntax would have been ambiguous and thus hard for the compiler to understand.

Personally, I do not see the great difference between "new (MM) int;" and "delete (MM) p;" - both seem to have roughly the same pattern. The only real difference between the two seems to be that to resolve delete the compiler would have to do the type-checking to determine which overload (if any) belongs to each call. Maybe this does muck up the compiler implementation - I do not really know.

[edited by - null_pointer on April 29, 2003 7:56:02 AM]

Share this post


Link to post
Share on other sites
null_pointer: I agree with what you say, but I''m sorry to say that what you say isn''t standard (atleast yet). Send an email regarding this to Stroustrop and he may (or may not) take this under consideration for the next C++0x standardization meeting.

A note on the example code that you took from TC++PL: friend functions can not be defined within the class, or they would be non-friend member functions.



Update GameDev.net system time campaign - success at last

Share this post


Link to post
Share on other sites
quote:
null_pointer: I agree with what you say, but I'm sorry to say that what you say isn't standard (atleast yet). Send an email regarding this to Stroustrop and he may (or may not) take this under consideration for the next C++0x standardization meeting.


OK, I will try.

quote:
A note on the example code that you took from TC++PL: friend functions can not be defined within the class, or they would be non-friend member functions.


Just to be perfectly clear, that was not the example code from TC++PL. Now that I look over the paragraph, though, I can see where you might have thought that. I will edit that post to avoid confusing anyone else.

It was my understanding that friend functions defined within the class are automatically non-member functions. This would be useful for defining operators and certain non-member functions that cannot be static (like WinMain):

quote:
Excerpt from C++ Standard 14882-1998, $11.4.5 Friends

A function can be defined in a friend declaration of a class if and only if the class is a nonlocal class (9.8), the function name is unqualified, and the function has namespace scope.
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).


Also, it would appear that the function has implicit access to things within the lexical scope of the class, but since it is a friend this is more for convenience than anything else.

[edited by - null_pointer on April 29, 2003 7:53:32 AM]

Share this post


Link to post
Share on other sites
I cringe to even suggest this since it goes against what i'd consider good practice - but if you've got the memory allocated, already manually called your destructor (or don't care about it), then can't you use dealloc?

Theres probably something hideously wrong with this from a technical point of view, in which case i'd be interested in finding out..

[edited by - OrangyTang on April 29, 2003 8:04:03 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by null_pointer
OK, I will try.

Please keep us informed on any updates. Stroustrop almost always send replies on emails, it could take a while though.

quote:
Original post by null_pointer
It was my understanding that friend functions defined within the class are automatically non-member functions.

Seems like I was wrong on that point, I was thinking like my (non-compliant) compilator.



Update GameDev.net system time campaign - success at last

[edited by - dalleboy on April 29, 2003 8:27:52 AM]

Share this post


Link to post
Share on other sites