Delete override with options

I can override the global operator new with different parameters, so, for example, I can have:

 void* operator new (std::size_t size) throw (std::bad_alloc); void* operator new (std::size_t size, int num) throw (std::bad_alloc); 

which can be called separately as

 int* p1 = new int; // calls new(size_t) int* p2 = new(5) int; // calls new(size_t, int) 

since each of them can potentially use some other distribution scheme, I will need a separate delete() function for each. However, delete(void*) cannot be overloaded in the same way! delete(void*) is the only valid signature. So how can the above case be handled?

PS I do not suggest that this is a good idea. This happened to me, and so I discovered this "flaw" (at least in my opinion) in C ++. If the language allows redefinition of new , it must allow redefinition of delete , or it becomes useless. And so I was wondering if there is a way around this, and not if it is a good idea.

+6
source share
5 answers

If you track different memory areas that you allocate with different new overloads, you can mark them with the new version that was invoked.

Then in delete you can look at the address to find which new was called, and do something else in each case.

This way you can ensure that the correct logic is automatically associated with every other new overload.

As indicated in the comments below, performance overhead is associated with servicing the data that you use to track, and this logic will only work until the overloaded deletion is passed by anything selected using the default delete.

Regarding overhead tracking, it seems to me that the minimum utility method of tracking the type of distribution is to allocate the requested amount plus a small amount of extra space at the beginning of the allocated area in which you need to mark the type of request (in accordance with the requirements of conservative alignment). You can then look at this area of ​​the delete tag to determine which logic to follow.

+5
source

I can override the global operator new with different parameters

These are the placement allocation functions.

delete (void *) is the only valid signature.

Not.

First, some terminology: a delete expression, such as delete p , is not just a function call, it calls the destructor and then calls the deallocation function, which is some kind of operator delete overload, which is selected using overload resolution.

You can override operator delete with signatures according to the placement allocation function, but this overload will only be used if the constructor called by the new placement expression throws an exception, for example.

 struct E { E() { throw 1; } }; void* operator new(std::size_t n, int) throw(std::bad_alloc) { return new char[n]; } void operator delete(void* p, int) { std::puts("hello!"); delete[] (char*)p; } int main() { try { new (1) E; } catch (...) { puts("caught"); } } 

The function of freeing the placement corresponding to the form of the used expression of placement (in this case, it has the int parameter) is determined by the resolution of the overload and is called to free the storage.

That way you can provide the "delete placement" features, you just can't explicitly name them. You must remember how you selected the object and make sure you use the appropriate release.

+8
source

There is a deletion of the placement that corresponds to the new operator. And you cannot call it directly. This is because deleting a place is used only to free memory when creating a constructor for a new object.

 void *operator new(size_t, Area&); // placement new void operator delete(void*, Area&); // matching placement delete ... Area &area; SomeType *t=new(area) SomeType(); // when SomeType() throws then `delete(t,area)` from above is called // but you can't do this: delete (area) t; 

A common way to overcome this is to use the overloaded "destroy" function, which accepts all kinds of parameters.

 template<class T> void destroy(Area &a, T* &pt) //<-you can't do this with 'delete' { if (pt) { pt->~T(); // run the destructor a.freeMem(pt); // deallocate the object pt=NULL; // nulls the pointer on the caller side. } } 
+2
source

Simple answer: Do not do this. All forms without placing new are redundant in C ++ 11 and terribly dangerous, for example, returning a raw pointer. If you want to select objects in an arbitrary place, then use a class with the allocate function if it is a state or a free function if not. The best treatment for new and indeed delete is to exclude them from your program with a prejudice, with the possible exception of placement new .

Edit: The reason this is useless to you is because you are trying to use it for a purpose for which it is not intended. All you can use for additional parameters are things like logging or other behavior. You cannot change the basic semantics of new and delete . If you need stateful selection, you should use a class.

0
source

You're wrong. This is possible to ensure that the placement is removed.

-1
source

Source: https://habr.com/ru/post/920214/


All Articles