5 Expressions [expr]

5.3 Unary expressions [expr.unary]

5.3.4 New [expr.new]

The new-expression attempts to create an object of the type-id ([dcl.name]) or new-type-id to which it is applied. The type of that object is the allocated type. This type shall be a complete object type, but not an abstract class type or array thereof ([intro.object], [basic.types], [class.abstract]). It is implementation-defined whether over-aligned types are supported ([basic.align]). [ Note: because references are not objects, references cannot be created by new-expressions.  — end note ] [ Note: the type-id may be a cv-qualified type, in which case the object created by the new-expression has a cv-qualified type.  — end note ]

new-expression:
    ::opt new new-placementopt new-type-id new-initializeropt 
    ::opt new new-placementopt ( type-id ) new-initializeropt

new-placement:
    ( expression-list )
new-type-id:
    type-specifier-seq new-declaratoropt
new-declarator:
    ptr-operator new-declaratoropt 
    noptr-new-declarator
noptr-new-declarator:
    [ expression ] attribute-specifier-seqopt
    noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt
new-initializer:
    ( expression-listopt )
    braced-init-list

Entities created by a new-expression have dynamic storage duration ([basic.stc.dynamic]). [ Note: the lifetime of such an entity is not necessarily restricted to the scope in which it is created.  — end note ] If the entity is a non-array object, the new-expression returns a pointer to the object created. If it is an array, the new-expression returns a pointer to the initial element of the array.

If the auto type-specifier appears in the type-specifier-seq of a new-type-id or type-id of a new-expression, the new-expression shall contain a new-initializer of the form

( assignment-expression )

The allocated type is deduced from the new-initializer as follows: Let e be the assignment-expression in the new-initializer and T be the new-type-id or type-id of the new-expression, then the allocated type is the type deduced for the variable x in the invented declaration ([dcl.spec.auto]):

T x(e);

Example:

new auto(1);                    // allocated type is int
auto x = new auto('a');         // allocated type is char, x is of type char*

 — end example ]

The new-type-id in a new-expression is the longest possible sequence of new-declarators. [ Note: this prevents ambiguities between the declarator operators &, &&, *, and [] and their expression counterparts.  — end note ] [ Example:

new int * i;                    // syntax error: parsed as (new int*) i, not as (new int)*i

The * is the pointer declarator and not the multiplication operator.  — end example ]

Note: parentheses in a new-type-id of a new-expression can have surprising effects. [ Example:

new int(*[10])();               // error

is ill-formed because the binding is

(new int) (*[10])();            // error

Instead, the explicitly parenthesized version of the new operator 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 ]

When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array. [ Note: both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10]  — end note ] The attribute-specifier-seq in a noptr-new-declarator appertains to the associated array type.

Every constant-expression in a noptr-new-declarator shall be an integral constant expression ([expr.const]) and evaluate to a strictly positive value. The expression in a noptr-new-declarator shall be of integral type, unscoped enumeration type, or a class type for which a single non-explicit conversion function to integral or unscoped enumeration type exists ([class.conv]). If the expression is of class type, the expression is converted by calling that conversion function, and the result of the conversion is used in place of the original expression. [ Example: given the definition int n = 42, new float[n][5] is well-formed (because n is the expression of a noptr-new-declarator), but new float[5][n] is ill-formed (because n is not a constant expression).  — end example ]

When the value of the expression in a noptr-new-declarator is zero, the allocation function is called to allocate an array with no elements. If the value of that expression is less than zero or such that the size of the allocated object would exceed the implementation-defined limit, or if the new-initializer is a braced-init-list for which the number of initializer-clauses exceeds the number of elements to initialize, no storage is obtained and the new-expression terminates by throwing an exception of a type that would match a handler ([except.handle]) of type std::bad_array_new_length ([new.badlength]).

A new-expression obtains storage for the object by calling an allocation function ([basic.stc.dynamic.allocation]). If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function ([basic.stc.dynamic.deallocation]). If the allocated type is a non-array type, the allocation function's name is operator new and the deallocation function's name is operator delete. If the allocated type is an array type, the allocation function's name is operator new[] and the deallocation function's name is operator delete[]. [ Note: an implementation shall provide default definitions for the global allocation functions ([basic.stc.dynamic], [new.delete.single], [new.delete.array]). A C++ program can provide alternative definitions of these functions ([replacement.functions]) and/or class-specific versions ([class.free]).  — end note ]

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.

A new-expression passes the amount of space requested to the allocation function as the first argument of type std::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. For arrays of char and unsigned char, 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 ([basic.align]) 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 ]

The new-placement syntax is used to supply additional arguments to an allocation function. If used, overload resolution is performed on a function call created by assembling an argument list consisting of the amount of space requested (the first argument) and the expressions in the new-placement part of the new-expression (the second and succeeding arguments). The first of these arguments has type std::size_t and the remaining arguments have the corresponding types of the expressions in the new-placement.

Example:

  • new T results in a call of operator new(sizeof(T)),

  • new(2,f) T results in a call of operator new(sizeof(T),2,f),

  • new T[5] results in a call of operator new[](sizeof(T)*5+x), and

  • new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f).

Here, x and y are non-negative unspecified values representing array allocation overhead; the result of the new-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 the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.  — end example ]

Note: unless an allocation function is declared with a non-throwing exception-specification ([except.spec]), it indicates failure to allocate storage by throwing a std::bad_alloc exception (Clause [except], [bad.alloc]); it returns a non-null pointer otherwise. If the allocation function is declared with 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 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: 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 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 T initializes that object as follows:

The invocation of the allocation function is indeterminately sequenced with respect to the evaluations of expressions in the new-initializer. Initialization of the allocated object is sequenced before the value computation of the new-expression. It is unspecified whether expressions in the new-initializer are evaluated if the allocation function returns the null pointer or exits using an exception.

If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function ([class.free]), and the constructor ([class.ctor]). If the new expression creates an array of objects of class type, access and ambiguity control are done for the destructor ([class.dtor]).

If any part of the object initialization described above76 terminates 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: 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 begins with a unary :: operator, the deallocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type T or an array thereof, the deallocation 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 or array thereof, the deallocation function's name is looked up 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. Any non-placement deallocation function matches a non-placement allocation function. 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 the two-parameter form of a usual deallocation function ([basic.stc.dynamic.deallocation]) 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. [ Example:

struct S { 
  // Placement allocation function:
  static void* operator new(std::size_t, std::size_t); 

  // Usual (non-placement) deallocation function:
  static void operator delete(void*, std::size_t); 
}; 

S* p = new (0) S;   // ill-formed: non-placement deallocation function matches 
                    // placement allocation function 

 — 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 make a copy of any argument as part of the call to the allocation function, it is allowed to make a copy (of the same original value) as part of the call to the deallocation function or to reuse the copy made as part of the call to the allocation function. If the copy is elided in one place, it need not be elided in the other.

This may include evaluating a new-initializer and/or calling a constructor.