22

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 where;
}

What else could it do? Why and how could I sensibly overload placement operator new?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Are you asking for uses of overloading the new operator? That's a pretty broad question. – Alexander Rafferty Sep 09 '10 at 08:50
  • 4
    @Alexander Rafferty I'm asking specifically about uses of overloading placement new. I can't see any purpose in this specific case. – sharptooth Sep 09 '10 at 08:52
  • +1 for getting into the header files. – Chubsdad Sep 09 '10 at 09:25
  • +1, interesting question, that's why I like SO :) – Matteo Italia Sep 09 '10 at 09:35
  • 2
    Pedantically: You don't _overload_ operator new, you _replace_ it (or override it). Overloading means creating a new method/function using the same name as an existing one but with a different signature. When replacing a function, you use the identical signature. – Adrian McCarthy Apr 06 '11 at 20:35
  • @0xbaadf00d What’s the purpose of your comment? If you have any additional info to this question, post a link! If it’s just a complaint, then please remove it. It does not contribute anything to the informational value of this page. – Melebius Jun 18 '18 at 10:21
  • @Melebius Your comment doesn't provide any informational value either. You have doubled the amount of comments that don't provide any informational value. This site has been ruined by the people running it. Sure, this is a discussion for meta, but frankly my dear I don't give a damn. – 0xbaadf00d Jun 20 '18 at 06:49
  • It answers my other question. Unlike the accepted answer says - this code is actually necessary when compiling placement new on non-Microsoft environments, like STM. I figured that out using trial and error method to force compiler to compile placement new on STM. To replicate the behavior - make a class, then try to overwrite class instance with placement new on non-MS C++ code. Compiler refuses to compile it unless this overload is added. With MSVC it does nothing. But it is run, debugger enters a breakpoint set on it. – Harry Jan 04 '23 at 15:50

9 Answers9

17

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.")

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Wow. Visual C++ 9 happily allows that. – sharptooth Sep 09 '10 at 14:02
  • @sharptooth: What's your test program? Not surprising, it's illegal in the same way it's illegal to add things (in general) to the `std` namespace. The language itself is none the wiser, but the standard library forbids it. – GManNickG Sep 09 '10 at 14:36
  • I replaced void* operator new[](size_t, void* where) by going into my compiler's header files. It worked fine. Actually, I didn't replace it -- I removed it, to make it unusable, because it **is** unusable. – Paul Du Bois Aug 22 '12 at 04:49
  • @PaulDuBois: Huh? Bad idea to edit compiler files, now you get to build on one very special configuration only; for what gain? – GManNickG Aug 22 '12 at 04:55
  • @GManNickG Actually, now I get to *fail the build* on one very special configuration only. The gain is that I am informed if anyone in my codebase uses placement array operator new. The problems with that feature are well-documented. – Paul Du Bois Sep 27 '12 at 21:09
  • 2
    Not useful, You can still override class specific placement new operations. – 0xbaadf00d Jan 24 '18 at 08:24
4

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.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
  • 3
    One reason for implementing it might be to force the use of a particular memory allocator; this has come up for us when doing complex things on Windows where it was necessary to force the use of the allocator used by one particular DLL rather than another one. (Yes, different libraries were using different allocators. It all worked, as long as code matched `new` from one lib with `delete` from the same lib.) – Donal Fellows Sep 09 '10 at 09:16
  • The first sentence is wrong, placement new has a specific meaning. And placement new cannot be overloaded or replaced. – GManNickG Sep 09 '10 at 13:40
  • @GMan: You are right. There seems to be no specific name for `operator new` overloads that take additional parameters, although they are usually invoked using the placement syntax. – Bart van Ingen Schenau Sep 10 '10 at 08:19
  • 3
    @GMan: `new` called with extra arguments is called "placement new", whether or not that extra data is an address where the object should be constructed. From the standard "The *new-placement* syntax is used to supply additional arguments to an allocation function." (section `[expr.new]`). The first two sentences of the answer are correct. The last is wrong though, replacing `::operator new(size_t, void*)` is forbidden, so you can't add tracing. – Ben Voigt Dec 31 '11 at 03:06
3

One example is at Stroustrup's FAQ.

blgt
  • 8,135
  • 1
  • 25
  • 28
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • 1
    Honestly I don't get that example. – sharptooth Sep 09 '10 at 08:58
  • @sharptooth Found a similar example with some additional explanation [here](http://www.parashift.com/c++-faq/memory-pools.html) (though there were some slight inaccuracies) – blgt Aug 19 '14 at 08:44
1

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!

Jesus
  • 11
  • 1
  • 1
    Could you please provide an example? This question is not about using placement new from user code, it's about overloading the operator. – sharptooth Mar 04 '15 at 07:32
1

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).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
0

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.

Carl Cook
  • 372
  • 5
  • 8
  • 1
    The question was whether any other implementation was possible. What else could I possibly do except `return where;`? – sharptooth Sep 23 '13 at 06:56
  • Ah, I see. Well, you could do some checking to make sure that this address isn't already used, doesn't overlap with already allocated memory, or you could even adjust `where` to be better aligned (returning `where + n` bytes). None of this I've ever seen before in practice. – Carl Cook Sep 23 '13 at 09:35
  • It compiles, but are you sure your override is being called? – John Lindal Jun 07 '18 at 18:51
  • Yes I am sure (as I've had to use this in production code before). To verify this, put a throw into the function body, and then create a new instance of this type. – Carl Cook Jun 08 '18 at 02:52
0

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.

0

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.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • It is called placement new, e.g. the standard says: "This overhead may be applied in all array *new-expressions*, including those referencing the library function `operator new[](std::size_t, void*)` **and other placement allocation functions.**" – Ben Voigt Dec 31 '11 at 03:09
-1

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;             
}
RED SOFT ADAIR
  • 12,032
  • 10
  • 54
  • 92