1
T *p = ::operator new(sizeof(T));
new (p) T;

I wonder how that syntax is working, given that placement new is declared as:

void* operator new(std::size_t, void*)

The second argument void* seems point to the storage of the object, so how does C++ connect the new (p) T to the void*?

In gcc libsupc++ the implementation is simply:

// Default placement versions of operator new.
_GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }

_GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }

Is the compiler responsible for translating the syntax new(*T) T to the calling of a placement operator new?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
akanesora
  • 81
  • 6
  • placement new doesn't really do anything itself. What it does do is tell the compiler to construct a `T` at the place the provide `T*` points to. This is required as there is no way for you as a programmer to call an objects constructor. – NathanOliver Jul 05 '23 at 16:44
  • 2
    It's just a normal operator overload. Well, *almost* normal. `new T` will invoke `operator new(size_t)`. Then you can add any kind of arguments you want. For example you can create an `operator new(size_t, int)` which can be invoked like `new (123) T`. You can even have multiple arguments. – Some programmer dude Jul 05 '23 at 16:46
  • Similar to https://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new/8918942#8918942 – Mooing Duck Jul 05 '23 at 22:05
  • Note that the syntax is more general. You can put anything in `(...)` after `new`, and it will get passed to `operator new(size,...)`. – HolyBlackCat Jul 05 '23 at 22:11

2 Answers2

5

Is it compiler's responsibility to translate the syntax new(*T) T to the calling of a placement operator new?

Yes, exactly.

Placement new can not be implemented as a library function, it needs special handling from the compiler anyway. The actual implementation that you saw in the libsupc++ source code can be misleading here, as most of the crucial properties of a placement new call are not reflected by that implementation.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
  • *placement* new doesn't require any special handling by the compiler. It works exactly the same as any other new expression. People just get confused because we virtually never pass parameters to `new` – Mooing Duck Jul 05 '23 at 22:08
  • @MooingDuck What I meant was that `operator new` cannot be implemented as a library function *in general*. I did not mean to imply that placement `new` is a special case among the various `new` variants here. – ComicSansMS Jul 06 '23 at 06:34
  • Pedantically, `operator new` is almost always implemented as a library function in general :P. But you are correct that the `new` expression can't, since that also calls the constructor. – Mooing Duck Jul 06 '23 at 14:18
1

Using the regular new expression does two things: it calls the function operator new which allocates memory (but does NOT construct), and then it calls the constructor at that location, to create the object at that memory.

For placement new, the operator new(std::size_t, void*) is a no-op, and just returns the pointer that was passed in, and then the compiler calls the constructor at that location, to create the object at that memory.

//normal version                   calls these two functions
MyClass* pMemory = new MyClass;    void* pMemory = operator new(sizeof(MyClass));
                                   MyClass::MyClass(pMemory); //pseudo-syntax

You can also make your own custom new methods, which also work with this same general mechanism.

void* operator new(std::size_t, const char* name) {
    return get_memory_by_name(name);
}

const char* allocation_name = "complex_float";
std::complex<float>* c = new(allocation_name) std::complex<float>{};
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158