[expr.new] (original) (raw)

7 Expressions [expr]

7.6 Compound expressions [expr.compound]

7.6.2 Unary expressions [expr.unary]

7.6.2.8 New [expr.new]

The new-expression attempts to create an object of thetype-id or new-type-id ([dcl.name]) to which it is applied.

The type of that object is the allocated type.

[Note 1:

Because references are not objects, references cannot be created bynew-expressions.

— _end note_]

[Note 2:

The type-id can be a cv-qualified type, in which case the object created by the new-expression has a cv-qualified type.

— _end note_]

[Example 1: new auto(1); auto x = new auto('a'); template<class T> struct A { A(T, T); };auto y = new A{1, 2}; — _end example_]

The new-type-id in a new-expression is the longest possible sequence of new-declarators.

[Note 3:

This prevents ambiguities between the declarator operators &, &&,*, and [] and their expression counterparts.

— _end note_]

[Example 2: new int * i;

The * is the pointer declarator and not the multiplication operator.

— _end example_]

[Note 4:

Parentheses in a new-type-id of a new-expressioncan have surprising effects.

[Example 3:

new int(*[10])(); is ill-formed because the binding is(new int) (*[10])();

Instead, the explicitly parenthesized version of the newoperator can be used to create objects of compound types ([basic.compound]):

new (int (*[10])());allocates an array of 10 pointers to functions (taking no argument and returning int).

— _end example_]

— _end note_]

Every constant-expression in anoptr-new-declarator shall be a converted constant expression ([expr.const]) of type std​::​size_t and its value shall be greater than zero.

[Example 4:

Given the definition int n = 42,new float[n][5] is well-formed (because n is theexpression of a noptr-new-declarator), butnew float[5][n] is ill-formed (because n is not a constant expression).

Furthermore,new float[0] is well-formed (because 0 is the expressionof a noptr-new-declarator, where a value of zero results in the allocation of an array with no elements), but new float[n][0] is ill-formed (because 0 is the constant-expressionof a noptr-new-declarator, where only values greater than zero are allowed).

— _end example_]

If the expression in a noptr-new-declaratoris present, it is implicitly converted to std​::​size_t.

The value of the expression is invalid if

If the value of the expression is invalid after converting to std​::​size_t:

When the value of the expression is zero, the allocation function is called to allocate an array with no elements.

If the allocated type is an array, the new-initializer is a braced-init-list, and the expressionis potentially-evaluated and not a core constant expression, the semantic constraints of copy-initializing a hypothetical element of the array from an empty initializer list are checked ([dcl.init.list]).

[Note 5:

The array can contain more elements than there are elements in the braced-init-list, requiring initialization of the remainder of the array elements from an empty initializer list.

— _end note_]

[Note 6:

The lifetime of such an object is not necessarily restricted to the scope in which it is created.

— _end note_]

When the allocated type is “array of N T” (that is, the noptr-new-declarator syntax is used or thenew-type-id or type-id denotes an array type), the new-expression yields a prvalue of type “pointer to T” that points to the initial element (if any) of the array.

Otherwise, let T be the allocated type; the new-expressionis a prvalue of type “pointer to T” that points to the object created.

[Note 7:

Both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10].

— _end note_]

If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function.

If the allocated type is a non-array type, the allocation function's name isoperator new and the deallocation function's name isoperator delete.

If the allocated type is an array type, the allocation function's name isoperator new[]and the deallocation function's name isoperator delete[].

[Note 8:

The set of allocation and deallocation functions that can be called by a new-expressioncan include functions that do not perform allocation or deallocation; for example, see [new.delete.placement].

— _end note_]

If the new-expressiondoes not begin with a unary ​::​ operator and the allocated type is a class type T or array thereof, a search is performed for the allocation function's name in the scope of T ([class.member.lookup]).

Otherwise, or if nothing is found, the allocation function's name is looked up by searching for it in the global scope.

When it does so, the storage is instead provided by the implementation or provided by extending the allocation of another new-expression.

During an evaluation of a constant expression, a call to a replaceable allocation function is always omitted ([expr.const]).

The implementation may extend the allocation of a new-expression e1 to provide storage for a new-expression e2 if the following would be true were the allocation not extended:

[Example 5: void can_merge(int x) { std::unique_ptr<char[]> a{new (std::nothrow) char[8]}; std::unique_ptr<char[]> b{new (std::nothrow) char[8]}; std::unique_ptr<char[]> c{new (std::nothrow) char[x]}; g(a.get(), b.get(), c.get());} void cannot_merge(int x) { std::unique_ptr<char[]> a{new char[8]};try { std::unique_ptr<char[]> b{new char[x]};} catch (const std::bad_alloc& e) { std::cerr << "Allocation failed: " << e.what() << std::endl;throw;} } — _end example_]

When a new-expression calls an allocation function and that allocation has not been extended, thenew-expression passes the amount of space requested to the allocation function as the first argument of typestd​::​size_t.

That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array and the allocation function is not a non-allocating form ([new.delete.placement]).

For arrays ofchar, 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 fundamentalalignment requirement of any object type whose size is no greater than the size of the array being created.

[Note 9:

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_]

When a new-expression calls an allocation function and that allocation has been extended, the size argument to the allocation call shall be no greater than the sum of the sizes for the omitted calls as specified above, plus the size for the extended call had it not been extended, plus any padding necessary to align the allocated objects within the allocated memory.

The new-placement syntax is used to supply additional arguments to an allocation function; such an expression is called a placement new-expression.

Overload resolution is performed on a function call created by assembling an argument list.

The first argument is the amount of space requested, and has type std​::​size_t.

If the type of the allocated object has new-extended alignment, the next argument is the type's alignment, and has type std​::​align_val_t.

If no matching function is found then

and then overload resolution is performed again.

[Example 6:

Here, each instance of x is a non-negative unspecified value representing array allocation overhead; the result of thenew-expression will be offset by this amount from the value returned by operator new[].

This overhead may be applied in all array new-expressions, including those referencing a placement allocation function, except when referencing the library function operator new[](std​::​size_t, void*).

The amount of overhead may vary from one invocation of new to another.

— _end example_]

[Note 10:

If the allocation function has a non-throwing exception specification, it returns null to indicate failure to allocate storage and a non-null pointer otherwise.

— _end note_]

If the allocation function is a non-allocating form ([new.delete.placement]) that returns null, the behavior is undefined.

Otherwise, if the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.

[Note 11:

When the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved.

The block of storage is assumed to be appropriately aligned ([basic.align]) and of the requested size.

The address of the created object will not necessarily be the same as that of the block if the object is an array.

— _end note_]

A new-expression that creates an object of type Tinitializes that object as follows:

The invocation of the allocation function is sequenced before the evaluations of expressions in the new-initializer.

Initialization of the allocated object is sequenced before thevalue computation of thenew-expression.

If the new-expressioncreates an array of objects of class type, the destructor is potentially invoked ([class.dtor]).

If any part of the object initialization described above61terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression.

If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object's memory to be freed.

[Note 13:

This is appropriate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak.

— _end note_]

If the new-expression does not begin with a unary ​::​ operator and the allocated type is a class type T or an array thereof, a search is performed for the deallocation function's name in the scope of T.

Otherwise, or if nothing is found, the deallocation function's name is looked up by searching for it in the global scope.

A declaration of a placement deallocation function matches the declaration of a placement allocation function if it has the same number of parameters and, after parameter transformations ([dcl.fct]), all parameter types except the first are identical.

If the lookup finds a single matching deallocation function, that function will be called; otherwise, no deallocation function will be called.

If the lookup finds a usual deallocation function and that function, considered as a placement deallocation function, would have been selected as a match for the allocation function, the program is ill-formed.

For a non-placement allocation function, the normal deallocation function lookup is used to find the matching deallocation function ([expr.delete]).

In any case, the matching deallocation function (if any) shall be non-deleted and accessible from the point where the new-expression appears.

[Example 7: struct S { static void* operator new(std::size_t, std::size_t);static void operator delete(void*, std::size_t);}; S* p = new (0) S; — _end example_]

If a new-expression calls a deallocation function, it passes the value returned from the allocation function call as the first argument of type void*.

If a placement deallocation function is called, it is passed the same additional arguments as were passed to the placement allocation function, that is, the same arguments as those specified with the new-placement syntax.

If the implementation is allowed to introduce a temporary object or make a copy of any argument as part of the call to the allocation function, it is unspecified whether the same object is used in the call to both the allocation and deallocation functions.