As far as I know the new keyword performs the process of allocating memory and call constructor of object.
class X{
public:
int x;
X(int a):x(a){std::cout<<"X(int a)"<<std::endl;}
~X(){std::cout<<"Delete X"<<std::endl;}
};
int main()
{
X* ptr = new X{2};
// allocate mem sizeof(X);
// call constructor of X{2};
delete(ptr);
}
Also new operator can be modified like below code.
X* ptr = static_cast<X*>( operator new(sizeof(X)) );
new(ptr) X{2};
My question is how to allocate constructor to ptr?
The "new(ptr) X{2}" is implemented like this.
It looks like there is no code that associated with class constructors.
How does this call a constructor?
new expressions and operator new are not the same thing. Unfortunately, they have names that suggest that operator new is like e.g. an operator overload operator+ for the + operator, which is however not the case.
A new expression may call an operator new overload, but that is only for the allocation step you are talking about, which is why the standard library placement-new operator new implementation is just a noop.
The construction of the object, including the constructor call if any is to be done, is an intrinsic part of the semantics of the new expression itself that can't be modified. There is no function implementing it and there wouldn't (generally) be any way to implement the construction of an object other than using a new expression itself.
Also, note that your replacement for the allocating new expression is not correct with your example X. X has a non-trivial destructor and is therefore not an implicit-lifetime type. This means that an X object is created only by the placement-new expression in the second line. The result of the operator new call (and also the result of the static_cast) will not be pointing to any X object.
It should be
void* mem = operator new(sizeof(X));
X* ptr = new(mem) X{2};
instead, so that ptr is guaranteed to point to the newly created object.
In general, you also need to make sure that the pointer returned from operator new is suitably aligned for the type X. Otherwise, the placement-new expression will not work correctly.
Since C++17 there is the __STDCPP_DEFAULT_NEW_ALIGNMENT__ macro against which you can test alignment to verify that the standard library's global replaceable operator new implementations without std::align_val_t parameter will guarantee suitable alignment:
static_assert(alignof(X) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__);
If that is not satisfied you must use the std::align_val_t overload:
void* mem = operator new(sizeof(X), std::align_val_t{alignof(X)});
Also, note that you should then (and only then) call the corresponding operator delete with the alignment to deallocate the memory (otherwise without the alignment argument):
ptr->~X();
operator delete(mem, std::align_val_t{alignof(X)});
The allocating new X{2} and delete(ptr); expressions do all of this decision-making on which operator new and operator delete to use internally, based on knowing the type of the operand.
(The above alignment consideration applies to the global replaceable operator new/operator delete overloads. A user-replacement of these operator new overloads must also satisfy the same requirements. However, a custom overload (rather than a replacement) may have other behavior and might be called from these expressions as a result of overload resolution.)
Related
A placement-new expression that takes a single argument that is a pointer to pre-allocated memory will construct an object of type T in that memory.
Why does it call the standard placement-new operator void* operator new ( std::size_t count, void* ptr ); since the latter does nothing and just returns its pointer argument?
int x = 10;
int* p = new(&x) int{1024};
Could you explain the steps taken in the above by the compiler to construct a new int in the memory address of x?
Why doesn't the placement-new expression directly construct an object at the memory address it gets as a pointer, rather than calling an operator function that does nothing and just returns its pointer argument?
The general rule is that new (args...) T will call operator new(sizeof(T), args...), and this function is required to return void*. If this operator new call returns successfully, the object is then constructed into the memory pointed to by the return value.
This general rule is powerful enough to support both the ordinary new expression new int and the placement form new (&x) int without any special cases. These two expressions call different overloads of operator new, which is why the former allocates and the latter does not. No matter what, an object is constructed at the end (unless the operator new function failed by throwing an exception).
There is no need to have a special rule in the language that says operator new is not called by a placement new expression. Instead, the compiler can simply optimize the code by directly constructing the int object into &x without calling operator new first, since it already knows that the placement operator new will just return its second argument.
(Actually, the reality is a bit more complicated than this. If T is an array type, then operator new[] is called instead of operator new, and the compiler may request from operator new[] a greater amount of memory than the array will actually occupy, and adjust the returned pointer before constructing the array. There are also special rules relating to over-aligned types, and there actually is some special-casing for placement new and delete. These details are not relevant to this answer.)
It is considered undefined behavior to invoke SL operator delete on a non-null pointer that was not returned by the SL operator new, as described here for (1) and (2):
https://en.cppreference.com/w/cpp/memory/new/operator_delete
The behavior of the standard library implementation of this function is undefined unless ptr is a null pointer or is a pointer previously obtained from the standard library implementation of operator new(size_t) or operator new(size_t, std::nothrow_t).
It is therefore also undefined behavior to mix usages of operator new, operator delete and operator new[], operator delete[]. I can't find anything in the standard stating if this also holds for replacement operator new and operator delete that invoke a user's allocation method. As an example:
void* operator new(std::size_t p_size)
{
void *ptr = UserImplementedAlloc(p_size);
return ptr;
}
void* operator new[](std::size_t p_size)
{
void *ptr = UserImplementedAlloc(p_size);
return ptr;
}
void operator delete(void* p_ptr)
{
UserImplementedFree(p_ptr);
}
void operator delete[](void* p_ptr)
{
UserImplementedFree(p_ptr);
}
Would the following be undefined? Assuming UserImplementedAlloc always returns a correct address and never a nullptr.
struct Simple
{
explicit Simple(); //Allocates m_bytes
~Simple(); //Frees m_bytes
char * m_bytes;
};
/*Placement new is not replaced or overridden for these examples.*/
//Example A
{
//Allocates and invokes constructor
Simple* a = new Simple();
//Invokes destructor
a->~Simple();
//Deallocates
UserImplementedFree(static_cast<void*>(a));
}
//Example B
{
//Allocates
void* addr = UserImplementedAlloc(sizeof(Simple));
//Invokes constructor
Simple* b = new (addr) Simple();
//Invokes destructor and deallocates
delete b;
}
I'm not looking for lectures about if this is bad practice, I am simply trying to determine if this is defined behavior or not.
Your compiler's version of delete might know something, hidden in the implementation, about the deleted pointer that relies on the type.
First calling the destructor manually and then deleting a void* (because otherwise you would call the destructor twice) is not safe. You are not deleting the same pointer in C++ semantics. It is the same address at the assembly level and it might free the same amount of memory - or, do you really know that? You have fooled the compiler to delete a void* instead of the actual type.
Both examples are undefined behavior. Now that I've taken the time to look through the C++17 standard final draft, I've found the evidence I need.
Example A
With regards to operator new:
Allocation functions - § 6.7.4.1.2
If the request succeeds, the value returned shall be a
non-null pointer value (7.11) p0 different from any previously returned value p1, unless that value p1 was
subsequently passed to an operator delete
In example A we call a new-expression, Simple* a = new Simple(), which internally will call the appropriate operator new. We bypass operator delete when we call UserImplementedFree(static_cast<void*>(a)). Even though operator delete would invoke this function, and presumably do the same deallocation, the catch is that any subsequent calls to operator new can now potentially return a pointer that matches the address that a had. And a was never passed to operator delete. So we've broken the rule stated above.
Example B
delete-expression - § 8.3.5.2
...the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (4.5)
representing a base class of such an object (Clause 13). If not, the behavior is undefined. In the second
alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer
value that resulted from a previous array new-expression.
83 If not, the behavior is undefined.
In example B, we do not allocate addr through a new-expression. And then we attempt to use a delete-expression to deallocate it. Which violates the rule above.
What would defined behavior look like?
The main feature of these examples is the separation of construction from allocation, and separation of destruction from deallocation. The standard states the following:
new-expression - § 8.3.4.11
For arrays of char, unsigned char,
and std::byte, the difference between the result of the new-expression and the address returned by the
allocation function shall be an integral multiple of the strictest fundamental alignment requirement (6.11) of
any object type whose size is no greater than the size of the array being created. [ Note: Because allocation
functions are assumed to return pointers to storage that is appropriately aligned for objects of any type with
fundamental alignment, this constraint on array allocation overhead permits the common idiom of allocating
character arrays into which objects of other types will later be placed. — end note ]
So defined behavior could potentially look like this:
{
//Allocates bytes
char* bytes = new char[sizeof(Simple)];
//Invokes constructor
Simple* a = new ((void *)bytes) Simple();
//Invokes destructor
a->~Simple();
//Deallocates
delete[] bytes;
}
Once again, not necessarily good practice, but defined behaviour.
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 ::new is used instead of just new;
why an explicit cast to void* is required.
(This answer uses N4659, the final C++17 draft.)
Why ::new is used instead of just new
::new ensures that the operator new is looked up in the global scope. In contrast, the plain new first looks up in the scope of the class if T is a class type (or array thereof), and only then falls back to the global scope. Per [expr.new]/9:
If the new-expression begins with a unary :: operator, the
allocation function's name is looked up in the global scope.
Otherwise, if the allocated type is a class type T or array thereof,
the allocation function's name is looked up in the scope of T. If
this lookup fails to find the name, or if the allocated type is not a
class type, the allocation function's name is looked up in the global
scope.
For example, with
struct C {
void* operator new(std::size_t, void* ptr) noexcept
{
std::cout << "Hello placement new!\n";
return ptr;
}
};
The plain new will cause this function to be found, thus printing unwanted message, whereas ::new will 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:
These functions are reserved; a C++ program may not define functions that displace the versions in the C++ standard library
([constraints]). The provisions of [basic.stc.dynamic] do not apply
to these reserved placement forms of operator new and operator
delete.
(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 required
Although the global operator new(std::size_t, void*) may not be replaced, new versions of ::operator new can be defined. For example, suppose that the following declaration is placed in the global scope:
void* operator new(std::size_t, int* ptr) noexcept
{
std::cout << "Hello placement new!\n";
return ptr;
}
Then ::new(ptr) T will use this version instead of the global version, where ptr is a int* value. The pointer is explicitly cast to void* to ensure that the void* version of operator new (which we intend to call) wins in overload resolution.
From comment:
But why do we want to call exactly global new for void* if some
type has special overload of new for itself? Seems like normal
overloaded operator is more suitable - why it's not?
Normally, new is used for allocation purposes. Allocation is something the user should have control over. The user can roll out more suitable versions for a normal new.
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_copy is 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 use std::uninitialized_copy for their elements — they call std::allocator_traits<Allocator>::construct. This feature is used by std::scoped_allocator_adaptor.
Suppose I have a type template parameter T.
And suppose I have a std::aligned_storage as follows:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
I want to placement new a T into the storage.
What is the standard-compliant pointer value/type to pass to the placement new operator, and how do I derive that from storage?
new (& ???) T(a,b,c);
For example:
new (&storage) T(a,b,c);
new (static_cast<void*>(&storage)) T(a,b,c);
new (reinterpret_cast<T*>(&storage)) T(a,b,c);
new (static_cast<T*>(static_cast<void*>(&storage));
Which of the above (if any) are compliant, and if none, what is the better way?
The most paranoid way is
::new ((void *)::std::addressof(storage)) T(a, b, c);
Explanation:
::std::addressof guards against overloaded unary operator& on storage, which is technically allowed by the standard. (Though no sane implementation would do it.) The ::std guards against any non-top-level namespaces (or classes) called std that might be in scope.
(void *) (which in this case is the equivalent of a static_cast) ensures that you call the placement operator new taking a void * rather than something else like decltype(storage) *.
::new skips any class-specific placement operator news, ensuring that the call goes to the global one.
Together, this guarantees that the call goes to the library placement operator new taking a void *, and that the T is constructed at where storage is.
In most sane programs, though,
new (&storage) T(a,b,c);
should be sufficient.
The placement allocation function is described as follows (C++14 n4140 18.6.1.3):
void* operator new(std::size_t size, void* ptr) noexcept;
Returns: ptr.
Remarks: Intentionally performs no other action.
20.10.7.6 table 57 describes aligned_storage<Len, Align> thus:
The member typedef type
shall be a POD type suitable for use
as uninitialized storage for any object
whose size is at most Len and whose
alignment is a divisor of Align.
This implies that in your case, &storage is suitably aligned for holding an object of type T. Therefore, under normal circumstances1, all 4 ways you've listed of calling placement new are valid and equivalent. I would use the first one (new (&storage)) for brevity.
1 T.C. correctly pointed out in the comments that it is technically possible for your program to declare an overload of the allocation function taking a typename std::aligned_storage<sizeof(T), alignof(T)>::type*, which would then be selected by overload resolution instead of the library-provided 'placement new' version.
I would say this unlikely in at least 99.999% of cases, but if you need to guard against that as well, use one of the casts to void*. The direct static_cast<void*>(&storage) is enough.
Also, if you're paranoid to this level, you should probably use ::new instead of just new to bypass any class-specific allocation functions.
class X
{
public:
X (int);
// ...
};
We can place objects anywhere by providing an allocator function with extra arguments and then supplying such extra arguments when using new:
void* operator new(size_t, void *p)
{
return p;
} // explicit placement operator
void* buf = reinterpret_cast<void*>(0xF00F); // significant address
X*p2 = new(buf)X; //construct an X at ‘buf;’ invokes: operator new(sizeof(X),buf)
What does it means? What is reinterpret_cast and what it is doing here?
explain broadly.....
There are two ways you can call operator new. The first way I'm assuming you're familiar with:
X *p1 = new X;
With this usage you're telling the compiler to do two things:
allocate enough space to store an instance of X. This is done by calling the default allocator supplied by the standard runtime unless you globally overloaded operator new to do something different.
fill out X's data members and get it to a known initial state by calling one of X's constructors.
Now the second form of operator new presented in your code:
X*p2 = new(buf) X;
With this usage you're basically telling the compiler do not allocate space for X. Instead use the space provided by buf to construct this instance of X. Step 2 is still performed but step 1 is skipped.
The reinterpret_cast<void *> here is essentially telling the compiler whatever is at address 0xF00F, treat it as some generic data -- no type or size is associated with this data. This is equivalent to doing a raw C-style cast:
void* buf = (void*)0xF00F;
This is done to satisfy operator new's function signature:
void* operator new(size_t, void *p)
Note the generic pointer void *p -- that will take on buf's value passed in earlier. The cast is there to make their 'types' match. Also note that 0xF00F technically isn't a valid address but we'll pretend it is for this example.
And that is what the code above is doing, explained broadly.
'reinterpret_cast' is converting a pointer to another pointer type.
http://msdn.microsoft.com/en-us/library/e0w9f63b.aspx
void* buf = reinterpret_cast<void*>(0xF00o0F);
0xF0000F is converted to a 'void *' pointer.