When using placement new in generic code to construct an object at a specified address, the usage pattern is a bit different from usual code. For example, consider this implementation of uninitialized_copy: ([uninitialized.copy])
template <class It, class For>
For uninitialized_copy(It first, It last, For dest)
{
using T = typename std::iterator_traits<For>::value_type;
for (; first != last; ++first, (void)++dest)
::new (static_cast<void*>(std::addressof(*dest))) T(*first);
}
This post addresses the following points from the perspective of the standard:
why
::newis used instead of justnew;why an explicit cast to
void*is required.
(This answer uses N4659, the final C++17 draft.)
Why
::newis used instead of justnew::newensures that theoperator newis looked up in the global scope. In contrast, the plainnewfirst looks up in the scope of the class ifTis a class type (or array thereof), and only then falls back to the global scope. Per [expr.new]/9:For example, with
The plain
newwill cause this function to be found, thus printing unwanted message, whereas::newwill still find the global function and work properly.The global
operator new(std::size_t, void*)cannot be replaced because of [new.delete.placement]/1:(See How should I write ISO C++ Standard conformant custom new and delete operators? for more about overloading
operator new.)Why an explicit cast to
void*is requiredAlthough the global
operator new(std::size_t, void*)may not be replaced, new versions of::operator newcan be defined. For example, suppose that the following declaration is placed in the global scope:Then
::new(ptr) Twill use this version instead of the global version, whereptris aint*value. The pointer is explicitly cast tovoid*to ensure that thevoid*version ofoperator new(which we intend to call) wins in overload resolution.From comment:
Normally,
newis used for allocation purposes. Allocation is something the user should have control over. The user can roll out more suitable versions for a normalnew.In this case, however, we don't want to allocate anything — all we want to do is create an object! The placement new is more of a "hack" — its presence is largely due to the lack of syntax available for constructing an object at a specified address. We don't want the user to be able to customize anything. The language itself, however, doesn't care about this hack, though — we have to treat it specially. Of course, if we have something like
construct_at(which is coming in C++20), we will use it!Also note that
std::uninitialized_copyis intended for the simplest case where you just want to copy construct a sequence of objects in raw allocated space. The standard containers allow you to customize not only how the elements are allocated, but also how they are constructed, by means of an allocator. Therefore, they do not generally usestd::uninitialized_copyfor their elements — they callstd::allocator_traits<Allocator>::construct. This feature is used bystd::scoped_allocator_adaptor.