18.6 Dynamic memory management
头文件<new>定义一些在程序中管理动态内存分配的函数。同时定义了报告内存管理错误的部件。
Header <new> 概要
namespace std { class bad_alloc; class bad_array_new_length; struct nothrow_t {}; extern const nothrow_t nothrow; typedef void (*new_handler)(); new_handler get_new_handler() noexcept; new_handler set_new_handler(new_handler new_p) noexcept; } void* operator new(std::size_t size); void* operator new(std::size_t size, const std::nothrow_t&) noexcept; void operator delete(void* ptr) noexcept; void operator delete(void* ptr, const std::nothrow_t&) noexcept; void* operator new[](std::size_t size); void* operator new[](std::size_t size, const std::nothrow_t&) noexcept; void operator delete[](void* ptr) noexcept; void operator delete[](void* ptr, const std::nothrow_t&) noexcept; void* operator new (std::size_t size, void* ptr) noexcept; void* operator new[](std::size_t size, void* ptr) noexcept; void operator delete (void* ptr, void*) noexcept; void operator delete[](void* ptr, void*) noexcept;
18.6.1 内存申请和释放
1.除非另有说明,库版本的operator new和operator delete符合(3.7.4)的规定。
18.6.1.1 单对象形式
void* operator new(std::size_t size);
1.影响:通过单对象形式new表达式调用的申请函数来分配适当对齐的size字节来表示任一size大小的对象。
2.可更换的:一个C++程序可能定义一个函数,这个函数的签名取代在C++标准库里定义的默认版本。
3.必要行为:返回一个非空指针,指向适当对齐的内存;否则抛出一个 bad_alloc 错误。这个要求绑定到此函数的替换版本。
4.默认行为:
- 执行一个循环:在循环中,函数首先尝试分配请求的内存。未指定这次尝试是否调用C库函数malloc。
- 如果尝试成功,返回一个指向分配到的内存的指针。否则,如果现在的new_handler是一个空指针,抛出bad_alloc。
- 否则,分配函数调用现在的new_handler函数。如果被调用的函数返回了,重复循环。
- 当 成功分配到需要的内存 或 一个被调用的new_handler没有返回。
void* operator new(std::size_t size, const std::nothrow_t&) noexcept;
5.影响:和上面一样,除非C++程序首选空指针而不是bad_alloc异常作为错误指示,new表达式的placement版本会调用它。
6.可替换的:一个C++程序可能定义一个函数,这个函数的签名取代在C++标准库里定义的默认版本。
7.必要行为:返回一个指向适当对齐的内存的非空指针,或者返回一个空指针。这个operator new的不抛出异常版本返回一个指针,就像普通版本(可能被替换)一样。这个要求绑定到此函数的替换版本。
8.默认行为:调用operator new(size)。如果调用正常地返回,返回调用的结果。否则返回空指针。
9.[Example:
T* p1 = new T; // 失败返回bad_alloc T* p2 = new(nothrow) T; // 失败返回0
-end example]
void operator delete(void* ptr) noexcept;
10.影响:释放函数通过delete表达式调用,使得ptr的值无效。
11.可替换的:同上
12.要求: ptr应当是一个空指针 或 它的值应当是之前通过如上2个new表达式的返回值,且这个值还未被operator delete(void*)干预(intervening call)。如果调用正常地返回,返回调用的结果。否则返回空指针。
13.要求: 如果实现具有严格的指针安全性,则ptr应该是安全派生的指针。
14.默认行为:如果ptr为空,不做任何事。否则,收回之前通过operator new分配到的内存。
15.备注: 在什么条件下这样被收回的部分或全部内存将会通过一些调用分配(operator new,calloc,malloc,realloc均可)是未指定的。
(It is unspecified under what conditions part or all of such reclaimed storage will be allocated by subsequent calls to operator new or any of calloc, malloc, or realloc, declared in <cstdlib>. )
void operator delete(void* ptr, const std::nothrow_t&) noexcept;
16.影响: The deallocation function (3.7.4.2) called by the implementation to render the value of ptr invalid when the constructor invoked from a nothrow placement version of the new-expression throws an exception.
17.可替换的:同上
18.要求: 如果实现具有严格的指针安全性,则ptr应该是安全派生的指针。
19.默认行为:调用operator delete(ptr)
18.6.1.2 数组形式
void* operator new[](std::size_t size);
1.影响:通过数组形式的new表达式调用来分配size字节的适当对齐的内存来表示任一那个大小的或更小的数组对象。
2.可替换的:同上。
3.必要行为:和operator new(std::size_t)一样。这个要求绑定到替换的版本。
4.默认行为:返回operator new(size)。
void* operator new[](std::size_t size,const std::nothrow_t&) noexcept;
5.影响:同上,除非C++程序首选空指针而不是bad_alloc异常作为错误指示,new表达式的placement版本会调用它。
6.可替换的:同上。
7.必要行为: 返回一个非空指针,指向适当对齐的内存,或者返回一个空指针。这个要求绑定到此函数的替换版本。
8.默认行为: 调用operator new。如果调用正常地返回,返回调用的结果。否则返回空指针。
void operator delete[](void* ptr) noexcept;
9.影响: 这个释放函数通过delete表达式的数组形式调用,使得ptr的值无效。
10.可替换的: 同上。
11.要求: ptr应当是一个空指针 或 它的值应当是之前通过如上2个new表达式的返回值,且这个值还未被operator delete(void*)干预(intervening call)。
12.要求: 如果实现具有严格的指针安全性,则ptr应该是安全派生的指针。
13.默认行为: 调用operator delete(ptr)。
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;
14.影响: 当从new[]表达式的nothrow placement版本调用的构造函数引发异常时,这个实现 调用deallocation function使ptr的值无效。
15.可替换的:同上。
16.要求: 如果实现了具有严格的指针安全性,则ptr应该是安全派生的指针。
18.6.1.3 Placement形式
1.这些函数是保留的,一个C++程序不要定义替代标准C++库的这些函数。(3.7.4的)规定不适用于这些保留的operator new和operator delete的placement形式。
void* operator new(std::size_t size, void* ptr) noexcept;
2.返回值: ptr。
3.备注: 有意不执行其他操作。
4.[Example: 这在一个已知地址上构造一个对象是有用的。
void* place = operator new(sizeof(Something)); Something* p = new(place) Something();
-end example]
void* operator new[](std::size_t size, void* ptr) noexcept;
5.返回值: ptr。
6.备注: 有意不执行其他操作。
void operator delete(void* ptr, void*) noexcept;
7.影响: 有意不执行操作。
8.要求: 如果实现了具有严格的指针安全性,则ptr应该是安全派生的指针。
9.备注: 当在placement new表达式中调用了库的非数组placement operator new,初始化的任何部分因为抛出一个异常而终止时,调用默认函数。
void operator delete[](void* ptr, void*) noexcept;
10.影响: 有意不执行操作。
11.要求: 如果实现了具有严格的指针安全性,则ptr应该是安全派生的指针。
12.备注: 当在placement new表达式中调用了库的数组placement operator new,初始化的任何部分因为抛出一个异常而终止时,调用默认函数。
18.6.1.4 数据竞争(Data races)
1.为了确定是否存在数据竞争,库版本的operator new,用户定义的全局operator new以及C标准库函数calloc和malloc的行为就好像它们通过返回值仅访问和修改了被引用的内存一样。库版本的operator delete,用户定义的全局operator delete以及C标准库函数free的行为就好像它们通过第一个参数仅访问和修改了被引用的内存一样。C标准库函数realloc的行为就像它通过第一个参数和返回值仅访问和修改被引用的内存一样。通过这些函数的调用来分配和回收一个内存的特定单元应该以一个single total顺序发生,并且每个这样的回收行为应该按此顺序在下一次分配(如果有)之前发生。
18.6.2 内存分配错误(Storage allocation errors)
18.6.2.1 类bad_alloc
namespace std { class bad_alloc : public exception { public: bad_alloc() noexcept; bad_alloc(const bad_alloc&) noexcept; bad_alloc& operator=(const bad_alloc&) noexcept; virtual const char* what() const noexcept; }; }
1.类bad_alloc定义通过实现将异常抛出的对象类型 来报告内存分配失败。(The class bad_alloc defines the type of objects thrown as exceptions by the implementation to report a failure to allocate storage. )
bad_alloc() noexcept;
2.影响: 构造一个类对象bad_alloc。
3.备注: 在新构造的对象上调用what()的结果是实现定义的。
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
4.影响: copy一个bad_alloc对象。
virtual const char* what() const noexcept;
5.返回值:一个实现定义的NTBS。
18.6.2.2 类bad_array_new_length
namespace std { class bad_array_new_length : public bad_alloc { public: bad_array_new_length() noexcept; }; }
1.类bad_array_new_length定义通过实现将异常抛出的对象类型 来报告尝试分配一个小于0或大于实现定义的限制 大小的数组。
bad_array_new_length() noexcept;
2.影响:构造一个bad_array_new_length对象。
3.备注:在新构造的对象上调用what()的结果是实现定义的。
18.6.2.3 类型 new_handler
typedef void (*new_handler)();
1.当operator new()或operator new不能满足一个额外内存的请求时,类型handle function会被它们调用。
2.必要行为: 一个new_handler必须表现以下行为之一:
- 让更多的内存可用于分配,然后返回。
- 抛出一个bad_alloc异常或继承自bad_alloc的类。
- 终止程序执行,不返回给调用方。
18.6.2.4 set_new_handler
new_handler set_new_handler(new_handler new_p) noexcept;
1.影响:创建由new_p指定的函数作为当前的new_handler。
2.返回值:先前的new_handler。
3.备注: 初始的new_handler是一个空指针。
18.6.2.5 get_new_handler
new_handler get_new_handler() noexcept;
1.返回值: 现在的new_handler。[Note:这可能返回一个空指针值。 -end note]
18.7 类型认证(Type identification)
头文件<typeinfo>定义和由实现生成的类型信息有关的类型。也定义了两个用于报告动态类型认证错误的类型。
namespace std { class type_info; class bad_cast; class bad_typeid; }
18.7.1 类type_info
namespace std { class type_info { public: virtual ~type_info(); bool operator==(const type_info& rhs) const noexcept; bool operator!=(const type_info& rhs) const noexcept; bool before(const type_info& rhs) const noexcept; size_t hash_code() const noexcept; const char* name() const noexcept; type_info(const type_info& rhs) = delete; // cannot be copied type_info& operator=(const type_info& rhs) = delete; // cannot be copied }; }
1.类type_info描述了由实现生成的类型信息。这个类的对象有效地保存了一个指向这个类型名字的指针和比较二个类型相等的方法或对照顺序。类型的名字,编码规则,相对顺序,是未指定的并可能程序间有差异。
bool operator==(const type_info& rhs) const noexcept;
2.影响: 和rhs比较现在的对象。
3.返回值: 如果两个值描述相同的类型,返回true。
bool operator!=(const type_info& rhs) const noexcept;
4.返回值: !(*this == rhs)。
bool before(const type_info& rhs) const noexcept;
5.影响: 和rhs比较现在的对象。
6.返回值: 如果*this在实现的对照顺序里先于rhs,返回true。
size_t hash_code() const noexcept;
7.返回值: 一个未指定的值,除非在一个单一执行的程序内部,如果是任意两个相同对象,它会返回同样的值。
8.备注: 如果任意两个type_info对象不相同,实现应该返回不同值。
const char* name() const noexcept;
9.返回值: 一个实现定义的NTBS。
10.备注: 消息是一个空终止多字节string,适配并且表现像wstring。
18.7.2 类bad_cast
namespace std { class bad_cast : public exception { public: bad_cast() noexcept; bad_cast(const bad_cast&) noexcept; bad_cast& operator=(const bad_cast&) noexcept; virtual const char* what() const noexcept; }; }
1.类bad_cast定义由实现抛出异常错误的类型,来报告无效动态强制转换表达式(dynamic-cast)的执行。
bad_cast() noexcept;
2.影响: 构造一个类bad_cast的对象。
3.备注: 在最新构造的对象上调用what()的结果是实现定义的。
bad_cast(const bad_cast&) noexcept;
bad_cast& operator=(const bad_cast&) noexcept;
4.影响: copy一个bad_cast对象。
virtual const char* what() const noexcept;
5.返回值: 一个实现定义的NTBS。
6.备注: 消息是一个空终止多字节string,适配并且表现像wstring。
18.7.3 类bad_typeid
namespace std { class bad_typeid : public exception { public: bad_typeid() noexcept; bad_typeid(const bad_typeid&) noexcept; bad_typeid& operator=(const bad_typeid&) noexcept; virtual const char* what() const noexcept; }; }
1.类bad_typeid定义由实现抛出异常错误的类型,来报告一个typeid表达式的空指针。
bad_typeid() noexcept;
2.影响: 构造一个bad_typeid对象。
3.备注: 在最新构造的对象上调用whta()的结果是实现定义的。
bad_typeid(const bad_typeid&) noexcept;
bad_typeid& operator=(const bad_typeid&) noexcept;
4.影响: copy一个bad_typeid对象。
virtual const char* what() const noexcept;
5.返回值: 一个实现定义的NTBS。
6.备注: 消息是一个空终止多字节string,适配并且表现像wstring。
18.8 异常处理(Exception handling)
头文件<exception>定义一些在一个C++程序中与异常处理有关的类型和函数。
Header <exception> 概要
namespace std { class exception; class bad_exception; class nested_exception; typedef void (*unexpected_handler)(); unexpected_handler get_unexpected() noexcept; unexpected_handler set_unexpected(unexpected_handler f) noexcept; [[noreturn]] void unexpected(); typedef void (*terminate_handler)(); terminate_handler get_terminate() noexcept; terminate_handler set_terminate(terminate_handler f) noexcept; [[noreturn]] void terminate() noexcept; bool uncaught_exception() noexcept; typedef unspecified exception_ptr; exception_ptr current_exception() noexcept; [[noreturn]] void rethrow_exception(exception_ptr p); template<class E> exception_ptr make_exception_ptr(E e) noexcept; [[noreturn]] template <class T> void throw_with_nested(T&& t); template <class E> void rethrow_if_nested(const E& e); }
18.8.1 类exception
namespace std{ class exception{ public: exception() noexcept; exception(const exception&) noexcept; exception& operator=(const exception&) noexcept; virtual ~exception(); virtual const char* what() const noexcept; }; }
1.类exception定义了C++标准库部件中用于抛出对象异常的基类,并且在某些表达式中来报告程序运行期的错误。
2.每个标准库继承自exception的class T 必须有一个不会退出执行的公共地可访问的copy构造函数和copy赋值运算符。这些成员函数必须满足下列的后置条件:如果两个对象 lhs 和 rhs 都由动态类型T并且lhs一个rhs的copy,那么strcmp(lhs.what(),rhs.what())必须等于0。
exception() noexcept;
3.影响: 构造一个exception对象。
4.备注: 不抛出任何异常。
exception(const exception& rhs) noexcept;
exception& operator=(const exception& rhs) noexcept;
5.影响: copy一个exception对象。
6.后置条件: 如果*this和rhs都有动态类型异常 ,strcmp(what(),rhs.what()) == 0 。
virtual ~exception();
7.影响: 析构一个exception对象。
8.备注: 不抛出任何异常。
virtual const char* what() const noexcept;
9.返回值: 一个实现定义的NTBS。
10.备注: 消息是一个空终止多字节string,适配并且表现像wstring。返回值保留有效,直到从中获取返回值的异常对象被破坏或调用该异常对象的non-const成员函数。
18.8.2 类bad_exception
namespace std { class bad_exception : public exception { public: bad_exception() noexcept; bad_exception(const bad_exception&) noexcept; bad_exception& operator=(const bad_exception&) noexcept; virtual const char* what() const noexcept; }; }
1.类bad_exception定义了(15.5.2所述)抛出的对象的类型。
bad_exception() noexcept;
2.影响: 构造一个bad_exception对象。
3.备注: 在最新构造的对象上调用what()的结果是实现定义的。
bad_exception(const bad_exception&) noexcept;
bad_exception& operator=(const bad_exception&) noexcept;
4.影响: copy一个bad_exception对象。
virtual const char* what() const noexcept;
5.返回值: 一个实现定义的NTBS。
6.备注: 消息是一个空终止多字节string,适配并且表现像wstring。
18.8.3 异常终止(Abnormal termination)
18.8.3.1 类型terminate_handler
typedef void (*terminate_handler)();
1.终止异常处理时的一个被terminate()调用的handler function类型。
2.必要行为: 一个terminate_handler必须终止程序的执行并且不返回给调用者。
3.默认行为: 实现的默认terminate_handler调用abort()。·
18.8.3.2 set_terminate
terminate_handler set_terminate(terminate_handler f) noexcept;
1.影响: 建立由f指定的函数作为当前的处理函数来终止程序执行。
2.备注: 一个空指针值是否指向默认terminate_handler是未指定的。
3.返回值: 先前的terminate_handler。
18.8.3.3 get_terminate
terminate_handler get_terminate() noexcept;
1.返回值: 当前的terminate_handler。 [Note:可能是一个空指针值。 -end note]
18.8.3.4 terminate
[[noreturn]] void terminate() noexcept;
1.备注: 在调用throw表达式后立即生效时,由于多种原因(15.5.1)中的任何一个原因必须放弃异常处理时,由实现调用。也可以由程序直接调用。
2.影响: 调用当前的terminate_handler函数。 [Node: 一个默认的terminate_handler总被认为在这个上下文中是可调用的handler。 -end note]
18.8.4 uncaught_exception
bool uncaught_exception() noexcept;
1.返回值: 在当前线程初始化一个异常对象之后直到一个异常handler是激活的,为true。
2.备注: 当uncaught_exception()返回true,抛出一个可以导致terminate()的异常。
18.8.5 异常传播
typedef unspecified exception_ptr;
1.类型exception_ptr可用于引用异常对象。
2.exception_ptr必须满足NullablePointer(17.6.3.3)的要求。
3.二个非空值的exception_ptr实例当且仅当它们指向相同异常是相等的。
4.exception_ptr的默认构造函数产生该类型的空值。
5.exception_ptr不可隐式转换到任一arithmetic,enumeration,或者pointer类型。
6.[Note: 一个实现可能使用了引用计数的智能指针作为exception_ptr。 -end note]
7.For purposes of determining the presence of a data race, operations on exception_ptr objects shall access and modify only the exception_ptr objects themselves and not the exceptions they refer to. Use of rethrow_exception on exception_ptr objects that refer to the same exception object shall not introduce a data race. [Note: if rethrow_exception rethrows the same exception object (rather thanacopy), concurrent access to that rethrown exception object may introduce adatarace. Changes in the number of exception_ptr objects that refer to a particular exception do not introduce a data race. —end note]
exception_ptr current_exception() noexcept;
8.返回值: 引用当前已处理的异常或当前已处理的异常的copy的exception_ptr对象;如果未处理任何异常,则为null exception_ptr对象。被引用对象至少在存在一个引用该对象的exception_ptr对象时才保持有效。如果函数需要分配内存并且尝试失败,则它将返回一个指向bad_alloc实例的exception_ptr对象。尚不确定两次对current_exception的连续调用的返回值是否引用相同的异常对象。[Note: 也就是说,不确定current_exception每次调用时是否从创建一个新copy。 -end note] 如果尝试copy当前异常对象时引发了异常,则该函数将返回一个exceptio_ptr对象,该对象引用引发的异常,或者如果不可能,则返回bad_exception的实例。[Note: 抛出的异常的copy构造函数也可能失败,因此允许该实现替换bad_exception对象以避免无限递归]
[[noreturn]] void rethrow_exception(exception_ptr p);
9.要求: p不应该是一个空指针。
10.抛出: p指向对象的异常。
template<class E> exception_ptr make_exception_ptr(E e) noexcept;
11.影响: 创建一个指向e的一个copy的exception_ptr对象,就像:
try{ throw e; } catch(...){ return current_exception(); }
- [Note: 提供此函数是为了方便和高效。-end note]
18.8.6 nested_exception
namespace std { class nested_exception { public: nested_exception() noexcept; nested_exception(const nested_exception&) noexcept = default; nested_exception& operator=(const nested_exception&) noexcept = default; virtual ~nested_exception() = default; // access functions [[noreturn]] void rethrow_nested() const; exception_ptr nested_ptr() const noexcept; }; [[noreturn]] template<class T> void throw_with_nested(T&& t); template <class E> void rethrow_if_nested(const E& e); }
1.类nested_exception设计用于通过多重继承作为mixin。它捕获当前处理的异常并且为了之后的使用保存它。
2.[Note: nested_exception有一个用于成为多态类的虚析构函数。可以使用dynamic_cast测试其存在。 -end note]
nested_exception() noexcept;
3.影响: 构造函数调用current_exception() 并且保存其返回值。
[[noreturn]] void rethrow_nested() const;
4.影响: 如果nested_ptr()返回一个空指针,这个函数调用terminate()。否则,它抛出被*this捕获的保存的异常。
exception_ptr nested_ptr() const noexcept;
5.返回值: 被这个nested_exceptioon对象捕获后保存的异常。
[[noreturn]] template <class T> void throw_with_nested(T&& t);
Let U be remove_reference<T>::type.
6.要求: U是复制可构造的(CopyConstructible)。
7.抛出: 如果U不是从nested_exception派生的non-union类型,则是一个未指定类型的异常,该异常是同时从U和nested_exception派生并从std::forward<T>(t)构造的,否则是std::forward<T>(t)。
template <class E> void rethrow_if_nested(const E& e);
8.影响: 如果e的动态类型是公共地明确地从nested_exception派生的,调用dynamic_cast<const nested_exception&>(e).rethrow_nested()。
18.9 初始化列表(Initializer list)
头文件<initializer_list>定义一个类型。
Header <initializer_list> 概要
namespace std { template<class E> class initializer_list { public: typedef E value_type; typedef const E& reference; typedef const E& const_reference; typedef size_t size_type; typedef const E* iterator; typedef const E* const_iterator; initializer_list() noexcept; size_t size() const noexcept; // number of elements const E* begin() const noexcept; // first element const E* end() const noexcept; // one past the last element }; // 18.9.3 initializer list range access template<class E> const E* begin(initializer_list<E> il) noexcept; template<class E> const E* end(initializer_list<E> il) noexcept; }
initializer_list<E>的对象提供一个const E的对象数组的访问。[Note: 一组指针或一个指针加一个长度将是initializer_list的明显表示形式。initializer_list常被用于实现像8.5.4中规定的初始化列表。copy一个初始化列表不会copy基本元素。-end note]
18.9.1 Initializer list constructors
initializer_list() noexcept;
1.影响: 构造一个空的initializer_list对象。
2.后置条件: size() == 0
18.9.2 Initializer list acccess
const E* begin() const noexcept;
1.返回值: 一个指向array起点的指针。如果size()==0,begin()和end()的值是未指定的,但它们相等。const E* end() const noexcept;
2.返回值: begin()+size()
size_t size() const noexcept;
3.返回值: 数组中的元素数量。
4.复杂度: O(1)(常数时间)
18.9.3 Initializer list range access
template<class E> const E* begin(initializer_list<E> il) noexcept;
1.返回值: il.begin()
template<class E> const E* end(initializer_list<E> il) noexcept;
2.返回值: il.end()