new
operator
发展概述
C++17
1、allocation functions with explicit alignment
内容概述
cppreference new expression 整体描述了new expression的内容,它主要两个功能:
1、allocation
2、construction
其中"allocation"是通过调用allocation function来实现的,这些allocation function在 cppreference operator new, operator new[] 中进行了描述
cppreference operator new, operator new[]
一、在 cppreference operator new, operator new[] 中,给出了 new operator 的allocation function的function signature,显然这是符合uniform function model的。
二、在 cppreference new expression 中,将它们称为"allocation function",因为它们主要用于allocate memory,因此其中会讨论alignment的问题
三、关于new expression 和 allocation function之间的对应关系,参见:
1、"How to call allocation function" 章节
C++ implementation
通过 stackoverflow Is there any guarantee of alignment of address return by C++'s new operation? 中的内容可知:
The
new
operator callsmalloc
internally (see./gcc/libstdc++-v3/libsupc++/new_op.cc
) so this applies tonew
as well.
Alignment说明
C++对dynamic allocation的alignment进行了要求,它们(大多数情况)都要求保证alignment,显然这简化了programmer的操作、保证了performance。主要是在 cppreference operator new, operator new[] 中,对alignment进行了说明。
分为三种情况:
1、
void* operator new ( std::size_t count ); // (1)
This function is required to return a pointer suitably aligned to point to an object of the requested size.
2、placement new
void* operator new ( std::size_t count, void* ptr ); // (9)
不对alignment做任何处理,由programmer自己来处理alignment
3、alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
(since C++17)
void* operator new ( std::size_t count, std::align_val_t al ); // (3)
能够保证alignment。
C++17 __STDCPP_DEFAULT_NEW_ALIGNMENT__
一、__STDCPP_DEFAULT_NEW_ALIGNMENT__
是new expression
的default alignment,显然这个default alignment是能够大多数类型的alignment requirement的,就好比 malloc 的default alignment。
二、对于alignment requirement超过__STDCPP_DEFAULT_NEW_ALIGNMENT__
的,可以使用"C++17 allocation functions with explicit alignment"特性
三、cppreference __STDCPP_DEFAULT_NEW_ALIGNMENT__
expands to an std::size_t literal whose value is the alignment guaranteed by a call to alignment-unaware operator new (larger alignments will be passed to alignment-aware overload, such as operator new(std::size_t, std::align_val_t)
stackoverflow Is there any guarantee of alignment of address return by C++'s new operation?
A
The alignment has the following guarantee from the standard (3.7.3.½):
The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).
A
This is a late answer but just to clarify the situation on Linux - on 64-bit systems memory is always 16-byte aligned:
http://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
The address of a block returned by malloc or realloc in the GNU system is always a multiple of eight (or sixteen on 64-bit systems).
The new
operator calls malloc
internally (see ./gcc/libstdc++-v3/libsupc++/new_op.cc
) so this applies to new
as well.
The implementation of malloc
which is part of the glibc
basically defines MALLOC_ALIGNMENT
to be 2*sizeof(size_t)
and size_t
is 32bit=4byte and 64bit=8byte on a x86-32 and x86-64 system, respectively.
$ cat ./glibc-2.14/malloc/malloc.c:
...
#ifndef INTERNAL_SIZE_T
#define INTERNAL_SIZE_T size_t
#endif
...
#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
...
#ifndef MALLOC_ALIGNMENT
#define MALLOC_ALIGNMENT (2 * SIZE_SZ)
#endif
A
NOTE:
custom allocator时,是需要遵循alignment的
C++17 changes the requirements on the new
allocator, such that it is required to return a pointer whose alignment is equal to the macro __STDCPP_DEFAULT_NEW_ALIGNMENT__
(which is defined by the implementation, not by including a header).
This is important because this size can be larger than alignof(std::max_align_t)
. In Visual C++ for example, the maximum regular alignment is 8-byte, but the default new
always returns 16-byte aligned memory.
Also, note that if you override the default new
with your own allocator, you are required to abide by the __STDCPP_DEFAULT_NEW_ALIGNMENT__
as well.
stackoverflow Order between STDCPP_DEFAULT_NEW_ALIGNMENT and alignof(std::max_align_t)
With GCC and Clang on x86-64/Linux alignof(std::max_align_t)
and __STDCPP_DEFAULT_NEW_ALIGNMENT__
are both equal to 16
.
With MSVC on x86-64/Windows alignof(std::max_align_t)
is 8
and __STDCPP_DEFAULT_NEW_ALIGNMENT__
is 16
.
The standard defines the two terms corresponding to these quantities in [basic.align]/3:
An extended alignment is represented by an alignment greater than
alignof(std::max_align_t)
. [...] A type having an extended alignment requirement is an over-aligned type. [...] A new-extended alignment is represented by an alignment greater than__STDCPP_DEFAULT_NEW_ALIGNMENT__
.
A
1、std::max_align_t
: The alignment of the biggest scalar type
2、__STDCPP_DEFAULT_NEW_ALIGNMENT__
: The alignment of allocated memory
NOTE:
C++17引入
cppreference new expression
Creates and initializes objects with dynamic storage duration, that is, objects whose lifetime is not necessarily limited by the scope in which they were created.
Syntax
::(optional) new (placement_params)(optional) ( type ) initializer(optional) (1)
::(optional) new (placement_params)(optional) type initializer(optional) (2)
NOTE: 关于
::
operator,参见下面的"Allocation"章节
1) Attempts to create an object of type, denoted by the type-id type
, which may be
1 array type, and may include
2 a placeholder type specifier (since C++11), or include
NOTE: 其实就是
auto
用法
3 a class template name whose argument is to be deduced by class template argument deduction (since C++17).
NOTE: 并不清楚它的具体用法
2) Same, but type
cannot include parentheses:
Explanation
NOTE: 下面是对new expression的解释,基于原文的内容, 进行了一些划分。
What new
do?
The new
expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage.
NOTE: 做了两件事:
1) allocate storage
2) construct and initialize
What new
return?
The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.
NOTE: 它的返回值就是是一个value,更加具体说是address value
Array type
NOTE: 原文的这一段,是比较繁杂的,还没有读完。
If type
is an array type, all dimensions other than the first must be specified as positive integral constant expression (until C++14)converted constant expression of type std::size_t (since C++14), but (only when using un-parenthesized syntax (2)) the first dimension may be an expression of integral type, enumeration type, or class type with a single non-explicit conversion function to integral or enumeration type (until C++14)any expression convertible to std::size_t (since C++14). This is the only way to directly create an array with size defined at runtime, such arrays are often referred to as dynamic arrays:
int n = 42;
double a[n][5]; // error
auto p1 = new double[n][5]; // OK
auto p2 = new double[5][n]; // error: only the first dimension may be non-constant
auto p3 = new (double[n][5]); // error: syntax (1) cannot be used for dynamic arrays
Allocation
The new-expression allocates storage by calling the appropriate allocation function. If type
is a non-array type, the name of the function is operator new
. If type
is an array type, the name of the function is operator new[]
.
NOTE:
一、上述 "allocation function" ,其实就是 cppreference operator new, operator new[]
1、在 cppreference operator new, operator new[] 给出了new-expression 和 function signature的对应关系
2、需要注意的是, cppreference operator new, operator new[] 仅仅用于 "allocates storage",因此在其中讨论了alignment的问题。
As described in allocation function, the C++ program may provide global and class-specific replacements for these functions. If the new-expression begins with the optional ::
operator, as in ::new T
or ::new T[n]
, class-specific replacements will be ignored (the function is looked up in global scope). Otherwise, if T
is a class type, lookup begins in the class scope of T
.
NOTE:
一、这描述的是C++中常见的"use the name in the global namespace"技巧,参见
C++\Language-reference\Basic-concept\Organization\Scope\Scope-resolution-operator
章节。
How to call allocation function
When calling the allocation function, the new-expression passes the number of bytes requested as the first argument, of type std::size_t, which is exactly sizeof(T)
for non-array T
.
new expression | allocation function | allocation function (C++17) |
---|---|---|
new T; |
operator new(sizeof(T)) |
operator new(sizeof(T), std::align_val_t(alignof(T)))) |
new T[5]; |
operator new[](sizeof(T)*5 + overhead) |
operator new(sizeof(T)*5+overhead, std::align_val_t(alignof(T)))) |
new(2,f) T; |
operator new(sizeof(T), 2, f) |
operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f) |
NOTE:
上述内容是摘自原文:
new T; // calls operator new(sizeof(T)) // (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T)))) new T[5]; // calls operator new[](sizeof(T)*5 + overhead) // (C++17) or operator new(sizeof(T)*5+overhead, std::align_val_t(alignof(T)))) new(2,f) T; // calls operator new(sizeof(T), 2, f) // (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
Overhead
NOTE:
原文的这一段解释了为什么要使用"overhead"。通过下面的描述来看,主要出于两个意图,参见下面的内容。
Array allocation may supply unspecified overhead, which may vary from one call to new to the next, unless the allocation function selected is the standard non-allocating form. The pointer returned by the new-expression will be offset by that value(指的是 overhead ) from the pointer returned by the allocation function.
NOTE:
1、上面这段话中的"the standard non-allocating form"指的是placement new。
Many implementations use the array overhead to store the number of objects in the array which is used by the delete[]
expression to call the correct number of destructors.
NOTE:
上面说明的是使用overhead的原因之一
In addition, if the new-expression is used to allocate an array of char
, unsigned char
, or std::byte
(since C++17), it may request additional memory from the allocation function if necessary to guarantee correct alignment of objects of all types no larger than the requested array size, if one is later placed into the allocated array.
NOTE:
上面说明的是使用overhead的原因之二
since C++14
NOTE:
未阅
since C++20
NOTE:
未阅
Placement new
NOTE:
参见
Placement-new
章节
Custom alignment requirement(since C++17)
NOTE:
关于这种用法,参见:
bfilipek New new() - The C++17's Alignment Parameter for Operator new()
When allocating an object whose alignment requirement exceeds __STDCPP_DEFAULT_NEW_ALIGNMENT__
or an array of such objects, the new-expression passes the alignment requirement (wrapped in std::align_val_t) as the second argument for the allocation function (for placement forms, placement_params
appear after the alignment, as the third, fourth, etc arguments). If overload resolution fails (which happens when a class-specific allocation function is defined with a different signature, since it hides the globals), overload resolution is attempted a second time, without alignment in the argument list. This allows alignment-unaware class-specific allocation functions to take precedence over the global alignment-aware allocation functions.
new T; // calls operator new(sizeof(T))
// (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T))))
new T[5]; // calls operator new[](sizeof(T)*5 + overhead)
// (C++17) or operator new(sizeof(T)*5+overhead, std::align_val_t(alignof(T))))
new(2,f) T; // calls operator new(sizeof(T), 2, f)
// (C++17) or operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)
Null pointer
NOTE:
If a non-throwing allocation function (e.g. the one selected by new(std::nothrow) T
) returns a null pointer because of an allocation failure, then the new-expression returns immediately, it does not attempt to initialize an object or to call a deallocation function. If a null pointer is passed as the argument to a non-allocating placement new-expression, which makes the selected standard non-allocating placement allocation function return a null pointer, the behavior is undefined.
Construction
NOTE:
原文这一段将如何进行initialization。
Memory leaks
The objects created by new-expressions (objects with dynamic storage duration) persist until the pointer returned by the new-expression is used in a matching delete-expression. If the original value of pointer is lost, the object becomes unreachable and cannot be deallocated: a memory leak occurs.
TODO
cnblogs C++ 内存分配操作符new和delete详解
stackoverflow Use new operator to initialise an array
A
You can use memcpy
after the allocation.
int originalArray[] ={1,2,3,4,5,6,7,8,9,10};
int *array = new int[10];
memcpy(array, originalArray, 10*sizeof(int) );
I'm not aware of any syntax that lets you do this automagically.
Much later edit:
const int *array = new int[10]{1,2,3,4,5,6,7,8,9,10};