澳门新葡亰平台官网CPP之内存分配

by admin on 2020年3月8日

C++ 委员会于上周在夏威夷科纳举办了一场官方 ISO
会议,以确定下一个国际标准 C++20 的功能集。

new & delete expression

C++历史

根据会议报告,C++20
的功能设计现已完成。计划于2019年7月在科隆举行的会议上,完成 C++20
的规范并发送一份委员会草案以供审查。

1. Introduction

A new expression allocates and constructs an object of a specified
type.

A new[] expression allocates and constructs an array of objects.

These expressions use the corresponding version of the library
operator new functions to allocate raw memory in which the
expression constructs an object or array of the specified type.

1. new 表达式分配和构造特定类型的对象。

2. new[] 表达式分配和构造对象数组。

  1. 这些表达式使用库函数 operator new
    的对应版本分配原始内存,并在该内存中构造特定类型的对象或数组。

A delete expression destroys a dynamically allocated object of a
specified type and frees the memory used by that object.

A delete[] expression destroys the elements of a dynamically
allocated array of a specified type and frees the memory used by the
array.

These expressions use the corresponding version of the library or
class-specific operator delete functions to free raw memory that
held the object or array.

1. delete 表达式销毁特定类型的动态分配对象,并释放该对象所用的内存。

  1. delete[]
    表达式销毁特定类型动态分配数组的元素,并释放该数组所使用的内存。

  2. 这些表达式使用库函数或类特定的 operator delete
    函数的对应版本来释放保存对象或数组的原始内存。

早期C++

•1979: 首次实现引入类的C(C with Classes first implemented)

1.新特性:类、成员函数、继承类、独立编译、公共和私有访问控制、友元、函数参数类型检查、默认参数、内联函数、赋值符号重载、构造函数、析构函数、f()相当于f(void)、调用函数和返回函数(同步机制,不是在C++中)
2.库:并发任务程序库(不是在C++中)

•1982: 发布引入类的C之参考手册(C with Classes reference manual
published)

•1984: C84的实现,参考手册发布(C84 implemented, reference manual
published)

•1985: Cfront 1.0

1.新特性:虚函数、函数和操作符重载、引用、new和delete操作符、const关键词、范围解析运算符::
2.新加入的库:复数(complex)、字符串(string)、输入输出流(iostream)

•1985: 《C++编程语言第一版》(The C++ Programming Language, 1st
edition)

•1989: Cfront 2.0

1.新特性:多重继承、成员指针、保护访问控制、类型安全联接、抽象类、静态和常量成员函数、特定类的new和delete
2.新库:I/O 操作器

•1990: 《C++参考手册注解》(The Annotated C++ Reference Manual)
此书从设计层面讲述了该语言,包括一些还没有实现的特性,在ISO标准以前它成为实际上的标准。

1.新特性:命名空间、异常捕获、内部类

•1991: Cfront 3.0

•1991: 《C++编程语言第二版》(The C++ Programming Language, 2nd
edition)


上周会议确定添加至 C++20 草案的新特性:

2. How to work?

我们来看看 newdelete 表达式是如何工作的。例如,使用如下 new
表达式:

// new expression

string * sp = new string(“initialized”);

澳门新葡亰平台官网,实际上发生了以下步骤:

首先,该表达式调用名为 operator new
的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象;

接下来,运行该类型的一个构造函数,用指定初始化式构造对象;

最后,返回指向新分配并构造的对象的指针。

当使用如下 delete 表达式时:

delete sp;

将会删除堆上分配的对象,发生以下两个步骤:

首先,对 sp 指向的对象运行适当的析构函数;

然后,通过调用名为
operator delete
的标准库函数释放该对象所用内存。

标准C++

•1990 ANSI C++委员会成立(ANSI C++ Committee founded)

•1991 ISO C++委员会成立(ISO C++ Committee founded)

•1998 C++98(ISO/IEC14882:1998)

1.新特性:运行时类型信息[RTTI(dynamic_cast,
typeid)]、协变返回类型(covariant return types)、cast
操作符、可变型、布尔型、声明情况、模板例示、成员模板、导出
2.新库:容器、算法、迭代器、函数对象(STL中)、区域设置、位集合、值向量、自动指针(auto_ptr)、模块化字符串、输入输出流和复数

•1998 《C++编程语言第三版》(The C++ Programming Language, 3rd edition)

•1999
Boost由委员会成员成立,旨在开发新的高质量库以作为标准库的候选库(Boost
founded by the committee members to produce new high-quality candidate
libraries for the standard)

•2003 C++03 (ISO/IEC 14882:2003)
这是一个次要修订版本,修正了一些错误。

1.新特性:初始化值
搜集错误报告修复:125个,包括69号错误,该错误连续生成std::vector

•2006 性能技术报告[Performance TR (ISO/IEC TR 18015:2006) (ISO Store )
(2006 draft )]

•2007 2007扩展库第一报告[2007 Library extension TR1 (ISO/IEC TR
19768:2007) (ISO store ) (2005 draft )]
这个技术报告是C++库扩展,加入了以下内容:

1.源自Boost:引用包装器(Reference wrapper)、智能指针(Smart
pointers)、成员函数(Member function)、Result of
、绑定(Binding)、函数(Function)、类型特征(type
traits)、随机(Random)、数学特殊函数(Mathematical Special
Functions)、元组(Tuple)、数组(Array)、无序容器[Unordered
Containers包括哈希(Hash)]还有正则表达式(Regular Expressions)
2.源自C99:math.h中同时也是新加入C99的数学函数、空白字符类、浮点环境(Floating-point
environment)、十六进制浮点I/O操作符(hexfloat I/O
Manipulator)、固定大小整数类型(fixed-size integral
types)、长整型(the long long type)、va_copy、snprintf()
和vscanf()函数族,还有C99 的printf()与scanf()函数族的指定转换
TR1除了一些特殊函数,大部分都被囊括进C++11。

•2010 数学特殊函数技术报告[2010 Mathematical special functions TR
(ISO/IEC 29124:2010) (ISO Store ) (2010 draft )]
此TR是一个C++标准库扩展,加入了TR1中的部分特殊函数,但那些函数之前没有被包括进C++11:椭圆积分、指数积分、拉盖尔多项式
(Laguerre polynomials)、勒让徳多项式(Legendre
polynomials)、艾尔米特多项式(Hermite
polynomials)、贝塞尔(Bessel)函数、纽曼(Newmann)函数、β函数和黎曼(Riemann)ζ函数

•2011 C++11 (ISO/IEC 14882:2011) (ISO Store) (ANSI Store )
(Post-publication draft )
对C++程序员,在现有惯例标准化和抽象概念提升方面有大量的改变可用。

1.新语言特性:自动(auto)和类型获取(decltype)、默认和已删除函数(defaulted
and deleted
functions)、不可更改(final)和重载(override)、拖尾返回类型(trailing
return type)、右值引用(rvalue references)、移动构造函数(move
constructors)/移动赋值(move assignment)、作用域枚举(scoped
enums)、常量表达式(constexpr)和文字类型(literal
types)、列表初始化(list
initialization)、授权(delegating)和继承构造器(inherited
constructors)、大括号或等号(brace-or-equal)初始化器、空指针(nullptr)、长整型(long
long)、char16_t和char32_t、类型别名(type
aliases)、可变参数模板(variadic templates)、广义联合体(generalized
unions)、广义POD、Unicode字符串文字(Unicode string
literals)、自定义文字(user-defined
literals)、属性(attributes)、λ表达式(lambda
expressions)、无异常(noexcept)、对齐查询(alignof)和对齐指定(alignas)、多线程内存模型
(multithreaded memory model)、线程本地存储(thread-local
storage)、GC接口(GC interface)、range for(based on a Boost
library)、静态断言[static assertions(based on a Boost library)]
2.新库特性:原子操作库(atomic operations
library)、emplace()和贯穿整个现有库的右值引用的使用、std::initializer_list、状态性的和作用域内的分配器
(stateful and scoped
allocators)、前向列表(forward_list)、计时库(chrono
library)、分数库(ratio library)、新算法(new algorithms)、Unicode
conversion facets
3.源自TR1:除了特殊的函数,TR1中全部都被囊括进来
4.源自Boost:线程库(The thread
library)、异常指针(exception_ptr)、错误码(error_code)和错误情况(error_condition)、迭代器改进
[iterator improvements(std::begin, std::end, std::next,
std::prev)]
5.源自C:C风格的Unicode转换函数
6.搜集错误报告修复:363个错误在2008草案中被解决,另外有322个错误接着被修复。其中的错误包括530号,它使得std::basic_string对象相连。

•2011 十进制浮点技术报告[Decimal floating-point TR (ISO/IEC TR
24733:2011) (ISO Store ) (2009 draft )]
这个TR根据IEEE 754-2008浮点算数标准(Floating Point
Arithmetic):std::decimal::decimal32、std::decimal::decimal64、std::decimal::decimal128

•2012 标准C++基金会成立(The Standard C++ Foundation founded )

•2013 《C++编程语言第四版》The C++ Programming Language, 4th edition


  • Modules!

  • Coroutines!

  • staticthread_local, and lambda capture for structured
    bindings.

  • std::polymorphic_allocator<>.

  • std::midpoint and std::lerp.

  • std::execution::unseq execution policy.

  • std::ssize() free function that returns a sized
    size.

  • std::span usability enhancements.

  • Precalculated hash values in lookup.

operator new and operator delete Functions

未来发展

*2014 C++14 (2014 final draft )
C++标准的下一个小修订

1.新语言特性:变量模板(variable templates)、多态λ(polymorphic
lambdas)、λ动捕获(move capture for lambdas)、new/delete
elision、常量表达式函数放宽限制(relax restrictions on constexpr
functions)、二值文本(binary literals)、数字分隔符(digit
separators)、函数返回类型推演(return type deduction for
functions)、用大括号或等号初始符集合初始化类
2.新库特性:std::make_unique、std::shared_mutex和std::shared_lock、
std::index_sequence、std::exchange、std::quoted,还有许多针对现有库的小改进,比如一些算法的双距离重载
(two-range overloads for some
algorithms)、类型特征的类型别名版本(type alias versions of type
traits)、用户定义字符串(user-defined
string)、持续期(duration)和复杂数字文本(complex number
literals)等等
3.搜集错误报告修复:149号库(149 library issues)
基础库技术规范(Library fundamentals TS),
文件系统技术规范(Filesystem TS)和其他专业技术规范( experimental
technical specifications)

•2017 C++17
C++标准的下一个主要修订

而以下的特性已在本次会议或之前的会议上获得了 C++20 批准,但尚未添加到
C++20
中,因为目前仍在完成规范。它们有望在2019年7月的科隆会议上被加入,不过由于时间限制,可能无法完成所有工作。

1. The operator new and operator delete Interface

operator newoperator delete
函数有两个重载版本(一个抛异常,一个不抛异常),每个版本支持相关的 new
表达式和 delete 表达式:

void *operator new(size_t);        // allocate an object

void *operator new[](size_t);      // allocate an array

void *operator delete(void*);      // free an object

void *operator delete[](void*);    // free an array

虽然 operator newoperator delete 函数的设计意图是供 new
表达式使用,但它们也是标准库中的可用函数。我们可以使用它们来获得未构造的原始内存,它们有点类似
allocate 类的 allocatordeallocate 成员。

  • Expansion statements.

  • The C++20 synchronization library.

  • std::format.

  • constexpr std::vector.

  • Allow constexpr allocation, but disallow allocations that are not
    deleted at compile time.

  • constexpr std::type_info::operator==.

  • New conceptification of iterators.

  • Monadic operations for std::optional.

  • std::source_location.

  • std::flatmap.

  • std::flatset.

  • std::ostream_joiner.

  • Stack trace library.

  • std::byteswap.

  • constinit.

  • Deprecating some uses of volatile.

  • Implicit creation of objects for low-level object
    manipulation.

  • using enum.

2. allocator and deallocate

std::allocator::allocate

pointer allocate (size_type n, allocator<void>::const_pointer hint=0);

Allocate block of storage

Attempts to allocate a block of storage with a size large enough to
contain n elements of member type value_type (an alias of the
allocator‘s template parameter), and returns a pointer to the first
element.
The storage is aligned appropriately for objects of type value_type,
but they are not constructed.
In the standard default allocator, the block of storage is allocated
using ::operator new one or more times, and throws bad_alloc if it
cannot allocate the total amount of storage requested.

分配原始内存空间,参数 n
填要分配的元素的个数,返回值是指向新分配的对象的指针。

而下面的这些特性,早已在之前的会议上获得了 C++ 20 批准。

Parameters

n Number of elements (each of size sizeof(value_type)) to be
allocated.
        The member type size_type is an alias of size_t (in the
standard default allocator) size_t is an unsigned integral type. 
hintEither 0 or a value previously obtained by another call to
allocate and not yet freed with deallocate.
        When it is not 0, this value may be used as a hint to
improve performance by allocating the new block near the one
specified. The address of an adjacent element is often a good
choice.(hint如果不是默认值0,可以填写之前 allocate
返回的指针,这可以在一定程度上提高性能)

  • Concepts.

  • Contracts.

  • Ranges.

  • operator<=>.

  • A lot
    more constexpr features: consteval functions, std::is_constant_evaluatedconstexpr unionconstexpr try and catchconstexpr dynamic_cast and typeid.

  • Feature test
    macros.

  • std::span.

  • Synchronized
    output.

  • std::atomic_ref.

Return value

A pointer to the initial element in the block of storage.

pointer and const_pointer are member types (defined as aliases of
T* and const T* respectively in std::allocator<T>).

The standard default allocator throws bad_alloc if it cannot allocate
the requested amount of storage.

 

std::allocator::deallocate

void deallocate (pointer p, size_type n);

Release block of storage

Releases a block of storage previously allocated with member allocate
and not yet released.
The elements in the array are not destroyed by a call to this
member function.
In the default allocator, the block of storage is at some point
deallocated using ::operator delete (either during the function
call, or later).

回收 p 指向的“可容纳 n 个元素”的内存空间

总之,C++20 应该会是一个像 C++11 那样的大版本。

3. Placement new Expressions

  1. 标准库函数 operator newoperator deleteallocator
    allocatedeallocate 成员的低级版本,它们都分配但不初始化内存。

  2. allocator 的成员 construct(执行对象的构造函数)
    destroy(执行对象的析构函数) 也有两个低级选择,这些成员在由
    allocator 对象分配的空间中初始化和销毁对象。

  3. 类似于 construct 成员,有第三种 new 表达式,称为定位
    new
    定位 new
    表达式在已分配的原始内存中初始化一个对象,它与 new
    的其他版本的不同之处在于,它不分配内存。相反,它接受指向已分配但未构造内存的指针,并在该内存中初始化一个对象。实际上,定位
    new 表达式使我们能够在特定的、预分配的内存地址构造一个对象。

operator new

throwing (1)

void* operator new (std::size_t size) throw (std::bad_alloc);

nothrow (2)

void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();

placement (3)

void* operator new (std::size_t size, void* ptr) throw();
其中第三种形式即为定位 new。

定位 new 表达式的形式是:

 new (place_address) type
 new (place_address) type (initializer-list)
 

返回值:place_address

其中 place_address 必须是一个指针,而 initializer-list
提供了(可能为空的)初始化列表,以便在构造新分配的对象时使用。

定位 new 表达式比 allocator 类的 construct 成员更灵活。定位 new
表达式初始化一个对象的时候,它可以使用任何构造函数,并直接建立对象。construct
函数总是使用拷贝构造函数。

例如,可以用下面两种方式之一,从一对迭代器初始化一个已分配但未构造的
string 对象:

     allocator<string> alloc;


string *sp = alloc.allocate(2); // allocate space to hold 2 strings


// two ways to construct a string from a pair of iterators
     new (sp) string(b, e);                    // construct directly in place
     alloc.construct(sp + 1, string(b, e));   // build and copy a temporary

定位 new 表达式使用了接受一对迭代器的 string 构造函数,在 sp
指向的空间直接构造 string 对象。而当调用 construct
函数的时候,必须首先从迭代器构造一个 string
对象(临时对象),以获得传递给 constructstring
对象,然后,该函数使用 string 的拷贝构造函数,将匿名临时 string
对象复制到 sp 指向的对象中。

通常,这些区别是无关紧要的:例如对于值型类而言,在适当的位置直接构造对象与构造临时对象并进行复制之间没有太大差别,并且性能差别也微乎其微。

但对某些类而言,使用拷贝构造函数是不可能的(因为复制构造函数是私有的),或者是应该避免的,在这种情况下,也许有必要使用定位
new 表达式来直接构造对象。

据透露,工具研究小组 SG15 决定创建一个
C++ 生态系统技术报告,该报告将描述新模块化 C++
世界中工具(构建系统等)的最佳实践和最新技术。

小结

参考:

1.

C++中的new运算符,具体工作流程如下:

1.调用标准库函数operator new申请原始内存

2.调用place new表达式,执行类的构造函数

3.返回内存地址

而delete操作符的工作是:

1.调用对象的析构函数

2.调用标准库函数operator delete释放内存

2.

分配原始内存的三种手段:

  1. 使用malloc

  2. 使用operator new

  3. allocator的allocate函数

这三者从上到下,是一个由低级到高级的过程。

实际上标准库函数 allocate 就是通过标准库函数 operator new 实现,而
operator new 通常也是通过 malloc 来实现。

执行构造函数,有两种手段:

  1. 使用placement new运算符

  2. 使用allocator的construct函数

实际上标准库函数 construct 的内部就是通过 placement new 来实现的

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图