How could I sensibly overload placement operator new?
C++ allows overloading operator new
- both global and per-class - usual operator new
, operator new[]
used with new[]
statement and placement operator new
separately.
The former two of those three are usually overloaded for using customized allocators and adding tracing. But placement operator new
seems pretty straightforward - it actually does nothing inside. For example, in Visual C++ the default implementation just returns the address passed into the call:
//from new.h
inline void* operator new( size_t, void* where )
{
return wher开发者_运维百科e;
}
What else could it do? Why and how could I sensibly overload placement operator new
?
The correct answer is you cannot replace operator placement new.
§18.4.1.3 Placement forms
These functions are reserved, a C++ program may not define functions that displace the versions in the Standard C++ library.
The rationale: The only purpose of the allocation and deallocation operators is to allocate and deallocate memory, so when given memory nothing more should be done. (The standard specifically notes that these functions "Intentionally perform no other action.")
Technically, a placement operator new
is any operator new
that takes additional arguments besides the size of the memory needed.
So, new(std::nothrow) X
uses a placement operator new
and so does new(__FILE__, __LINE__) X
.
The only reason for overriding the operator new(size_t, void*)
could be to add tracing information, but I think the need for that will be pretty low.
One example is at Stroustrup's FAQ.
The most obvious override would be to copy this implementation.
Another sensible one would be to add some checks (for example, verifying that there is no "bound-marker" within the request zone).
I think however that the point is more than you HAVE to override it, as soon as you override the others (for a given class), because of the mechanics of name look up (or not overriding it to prevent its use, that's fine too, but it's a conscious decision).
To define your own memory management for a prereserved area is one nice use.
To have different views on the same physical data (no need to move the data) is other interseting use. It also allows you reading a structured file as chars on a buffer and then, the superimposition of the their logical structure by defining an object of that the class over the buffer. The combination of this thing with the memory mapping of files, can provide big improvements in performance. The memory mapped hardware... So, thousand applications!
I've seen an example where two-argument new [] was overwritten to return memory blocks pre-filled with the char passed as the additional argument. I don't remember what the original code used (probably memset()), but it was functionally something like this:
#include <iostream>
#include <algorithm>
#include <new>
void* operator new [](size_t n, char c)
{
char* p = new char[n];
std::fill(p, p+n, c);
return p;
}
int main()
{
char* p = new('a') char[10];
std::cout << p[0] << p[1] << ".." << p[9] << '\n';
}
although I guess this wouldn't be called "placement" new because it does not perform placement. It could probably be useful if templated so that it can build arrays of any type, filled with a copy of the object passed as its second argument... but then, we have containers for that anyway.
I'm not exactly sure of the question, but the following overrides placement new at the class level:
struct Bar {
void* operator new(size_t /* ignored */, void* where) throw() { return where; }
};
int main() {
char mem[1];
Bar* bar = new(mem) Bar;
}
I believe this is legal C++ (and compiles and runs fine with gcc 4.4.6).
You are free to change the implementation of this operator as you see fit (including removing the throw()
clause, which will mean the compiler no longer checks the where
pointer for null before calling the constructor). Tread carefully though.
§18.4.1.3 is interesting. I believe this just applies to the global operator new function, not class specific ones.
The most important extra-functionality for placement new overload would be to check address alignment.
For example, lets assume some class requires 16-bytes alignment. Developer overloads new, new[], delete and delete[] - just to be sure everything is aligned properly.
Everything works fine to the moment when he tries to use his class with library which uses placement new... Library has no idea if/what alignment is required for the class and address it tries to "place" the object to might not be aligned - big boom.
The simplest example of such situation - try using std::vector<T> where T requires non-standard alignment.
Overload for placement new allows to detect if pointer is not aligned - might save hours of debugging.
My primary usage is to create a large array of objects. Its performing much better and has less overhead to allocate the memory in a whole block, i.e. using VirtualAlloc from Win32 (when programming windows). Then you just pass a ptr within that block to each objects placement new such as:
char *cp = new char[totalSize];
for(i = 0; i < count; i++, cp += ObjSize)
{
myClass *obj = new(cp) myClass;
}
精彩评论