现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

C++Primer第五版中的c++11特性归纳(四)

2019-04-29 06:29 工业·编程 ⁄ 共 2937字 ⁄ 字号 暂无评论

三十一、容器的非成员函数swap

在新标准库中,容器既提供成员函数版本的swap,也提供非成员版本的swap,而早期标准库版本只提供成员函数版本的swap。非成员版本的swap在泛形编程中是非常重要的,统一使用非成员版本的swap是一个好习惯。

三十二、容器insert成员的返回类型

在新标准下,接受元素个数或范围的insert版本返回指向第一个新加入元素的迭代器。(在旧版本中,这些操作返回void。)如果范围为空,不插入任何元素,insert操作会将第一个参数返回。

三十三、容器的emplace成员的返回类型

新标准引入了三个新成员:emplace_front、emplace和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应push_front、push和push_back,允许我们把元素放置在容器头部、一个指定位置之前或者容器尾部。当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。

emplace成员使用这些参数在容器管理的内存空间中直接构造元素。例如,假定c保存Sales_data元素:

//在c的末尾构造一个Sales_data对象

//使用三个参数的Sales_data构造函数

c.emplace_back("978-059", 25, 15.99);

//错误,没有接受3个参数的push_back版本

c.push_back("978-059", 25, 15.99);

//正确,创建一个临时的Sales_data对象传递给push_back

c.push_back(Sales_data("978-059", 25, 15.99));

其中对emplace_back的调用和第二个push_back调用都会创建新的Sales_data对象。在调用emplace_back时,会在容器管理的内存空间中直接创建对象。而调用push_back则会创建一个局部临时对象,并将其压入容器中。

三十四、shrink_to_fit

在新标准库中,我们可以调用shrink_to_fit来要求deque、vector和string退回不需要的内存空间,此函数指出我们不再需要任何多余的内存空间。但是,具体的实现可以选择忽略此请求。也就是说,使用shrink_to_fit也并不保证一定退回内存空间。

三十五、string的数值转换函数

新标准引入了多个函数,可以实现数值数据与标准库string之间的转换:

int i = 42;

string s = to_string(i); //将整数i转换为字符表示形式

double d = stod(s);      //将字符串s转换为浮点数

三十六、关联容器的列表初始化

当定义一个map时,必须既指明关键字类型又指明值类型;而定义一个set时,只需指明关键字类型,因为set中没有值。每个关联容器都定义了一个默认构造函数,它创建一个指定类型的空容器。我们也可以将关联容器初始化为另一个同类型容器的拷贝,或是从一个值范围来初始化关联容器,只要这些值能转化为容器所需类型就可以。在新标准下,我们也可以对关联容器进行值初始化

map<string, size_t> word_count; //空容器

//列表初始化

set<string> exclude = {"the", "but", "and", "or", "an", "a"};

//三个元素:author将姓映射成名

map<string, string> authors = { {"Joyce", "James"},

{"Austen", "Jane"}

{"Dickens", "Charles"}};

与以往一样,初始化器必须能转换为容器中元素的类型。对于set,元素类型就是关键字类型。

当初始化一个map时,必须提供关键字类型和值类型。我们将每个关键字-值对包围在花括号中:{key, value}来指出他们一起构成了map中的一个元素。在每个花括号中,关键字是第一个元素,值是第二个。

三十七、pair的列表初始化

对一个map进行inset操作时,必须记住元素类型是pair。通常,对于想要插入的数据,并没有一个现成的pair对象。可以在insert的参数列表中创建一个pair:

word_count.inset(word,1);

word_count.inset(make_pair(word, 1));

word_count.inset(pair<string, size_t>(word, 1));

word_count.inset(map<string, size_t>::value_type(word, 1));

在新标准下,创建一个pari最简单的方法是在参数列表中使用花括号初始化。也可以调用make_pair或显式构造pair。最后一个insert中调用的参数:

map<string, size_t>::value_type(s, 1)

构造一个恰当的pair类型,并构造一个新对象,插入到map中。

三十八、智能指针

为了更容易(同时也更安全)地使用动态内存,新的标准库提供了两种指针指针(smart pointer)类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它复制自动释放所指向的对象。新标准库提供的这两种智能指针的区别在于管理底层指针的方式:shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。

三十九、动态分配对象的列表初始化

我们可以使用直接初始化方式来初始化一个动态分配的对象。我们可以使用传统的构造方式(使用圆括号),在新标准下,也可以使用列表初始化(使用花括号):

int *pi = new int(1024); //pi指向的对象的值为1024

string *ps = new string(10, '9'); //*ps为"9999999999"

//vector有10个元素,值依次从0到9

vector<int> *pv = new vector<int>{0,1,2,3,4,5,6,7,8,9};

也可以对动态分配的对象进行值初始化,只需在类型名后跟一对空括号即可:

string *ps1 = new string; //默认初始化为空string

string *ps = new string(); //值初始化为空string

int *pi1 = new int; //默认初始化;*pi1的值未定义

int *pi2 = new int(); //值初始化为0;*pi2为0

四十、auto和动态分配

如果我们提供了一个括号包围的初始化器,就可以使用auto从此初始化器来推断我们想要分配的对象的类型。但是,由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器时才可以使用auto:

auto p1 = new auto(obj); //p指向一个与obj类型相同的对象,该对象用obj进行初始化

auto p2 = new auto(a, b, c);//错误,括号中只能由单个初始化器。

给我留言

留言无头像?