forward_list和array容器
新标准添加了forward_list
和array
容器。array
容器是内置数组的一种更安全更易于使用的替代方法。与内置数组一样,标准库提供的array
容器有固定大小。因此array
容器不支持添加和删除元素或调整容器大小的操作。forward_list
容器是具有最佳性能的手写单链表的替代。因此forward_list
容器不支持size
操作,因为与最佳性能的手写单列表相比,存储或计算其大小会产生开销。对于标准库中其他容器,size
操作保证是快速,常量时间操作。
新的标准库容器比以前的版本快得多。可以肯定的是标准库容器通常表现得比最精心设计的替代品要好。现代C ++程序应该使用标准库容器而不是像数组这样的更原始的结构。
关于array
容器更详细的信息可参考header <array>。
关于forward_list
容器更详细的信息可参考header <forward_list>。
容器的cbegin和cend函数
新标准中引入了容器的cbegin
和cend
函数,用于返回const
型的迭代器。同时新标准下可以使用auto
声明,这也简化了具体类型的声明。而之前版本中,在声明迭代器时我们必须明确指明具体的迭代器类型。
Code:
// type is explicitly specified
list<string>::iterator it5 = a.begin();
list<string>::const_iterator it6 = a.begin();
// iterator or const_iterator depending on a's type of a
auto it7 = a.begin(); // const_iterator only if a is const
auto it8 = a.cbegin(); // it8 is const_iterator
当auto
与begin
和end
一起使用时,我们得到的迭代器类型取决于容器类型。而使用cbegin
和cend
时无论容器的类型如何都会得到const_iterator
。
注:当不需要对容器元素进行写操作时,我们应该使用cbegin和cend。
容器的初始化器列表
新标准下,我们可以使用初始化器列表来初始化容器。
Code:
// each container has three elements, initialized from the given initializers
list<string> authors = {"Milton", "Shakespeare", "Austen"};
vector<const char*> articles = {"a", "an", "the"};
当我们这样做时,我们明确指定了容器中每个元素的值。对于除数组以外的容器类型,初始化器列表还隐式指定了容器的大小:容器将具有与初始化器列表一样多的元素
非容器成员函数swap
新标准下的标准库中,容器提供了成员和非成员版本的swap
函数。标准库的早期版本仅定义了swap
函数的成员版本。非成员交换在通用程序中极为重要。作为习惯,我们最好使用非成员版本的swap
函数。
Code:
vector<string> svec1(10); // vector with ten elements
vector<string> svec2(24); // vector with 24 elements
swap(svec1, svec2);
运行swap
函数之后,svec1
包含24个字符串元素,svec2
包含10个。除了数组之外,为了保证交换两个容器能最快完成,swap
函数不会交换元素本身,而是交换数据的内部结构。
除了数组,swap
不会复制,删除或插入任何元素,并保证在常数时间内完成。
容器成员insert的返回类型
新标准下,带有计数或范围的insert
版本将返回指向被插入的第一个元素的迭代器(而标准库的之前版本中,这样的操作将返回void
)。如果传给insert
的范围为空,则不插入任何元素,并且insert
将返回其第一个参数
Code:
list<string> lst;
list<string> lnd;
auto iter = lst.begin();
while (cin >> word)
iter = lst.insert(iter, word); // same as calling push_front
auto iter2 = lnd.insert(lnd.begin(), 2, "world");
// iter2 point the first "world" in lnd
容器成员emplace
新标准引入了三个新成员——emplace_front
,emplace
和emplace_back
,并且它们执行时是构造而不是复制元素。这些操作对应于push_front
,insert
和push_back
操作,因为它们允许我们将元素分别放在容器的前面,给定位置的前面或容器的后面。
当我们调用push
或insert
成员时,我们传递元素类型的对象,并将这些对象复制到容器中。当我们调用一个emplace
成员时,我们将参数传递给元素类型的构造函数。emplace
成员使用这些参数直接在容器管理的空间中构造元素。下面代码中我们假定c
对象是一个包含类Sales_data
元素的容器。
Code:
// construct a Sales_data object at the end of c
// uses the three-argument Sales_data constructor
c.emplace_back("978-0590353403", 25, 15.99);
// error: there is no version of push_back that takes three arguments
c.push_back("978-0590353403", 25, 15.99);
// ok: we create a temporary Sales_data object to pass to push_back
c.push_back(Sales_data("978-0590353403", 25, 15.99));
对emplace_back
的调用和对push_back
的第二次调用都创建了新的Sales_data
对象。在对emplace_back
的调用中,该对象直接在容器管理的空间中创建。对push_back
的调用会创建一个传送到容器上的本地临时对象。
emplace
函数的参数因元素类型而异。参数必须与元素类型的构造函数匹配:
Code:
// iter refers to an element in c, which holds Sales_data elements
c.emplace_back(); // uses the Sales_data default constructor
c.emplace(iter, "999-999999999"); // uses Sales_data(string)
// uses the Sales_data constructor that takes an ISBN, a count, and a price
c.emplace_front("978-0590353403", 25, 15.99);
注:emplace函数构造容器中的元素。这些函数的参数必须与元素类型的构造函数匹配。
shrink_to_fit
在新标准下,我们可以使用shrink_to_fit
来请求deque
、vector
或string
返回不需要的内存。 此功能表明我们不再需要任何多余的容量。我们无法保证调用shrink_to_fit
将返回内存。
shrink_to_fit
仅仅对deque
、vector
和string
有效;capacity
和reserve
仅仅对vector
和string
有效。
Code:
c.shrink_to_fit(); // request to reduce capacity() to equal size()
c.capacity(); // number of elements c can have before reallocation is necessary
c.reserve(n); // allocate space for a least n elements
字符串的数字转换函数
新标准引入了几个在数字数据和标准库字符串之间进行转换的函数:
int i = 42;
string s = to_string(i); // converts the int i to its character representation
double d = stod(s); // converts the string s to floating-point
字符串与数字数据之间的转换如下表所示:
函数 | 功能 |
---|---|
to_string(val); |
重载函数。返回val 的字符串表示形式。val 可以是任何算术类型。对于每一种浮点数类型、int或更大的整数类型,都有对应版本的to_string
|
stoi(s, p, b); stol(s, p, b); stoul(s, p, b); stoll(s, p, b); stoull(s,p,b);
|
返回具有类型int, long, unsigned long, long long, unsigned long long 的数字内容的s 的初始子字符串。b 表示用于转换的数字基数;b 默认为10。p 是指向size_t 的指针,在该指针中保存s 中第一个非数字字符的索引。 |
stof(s, p); stod(s, p); stold(s, p);
|
返回具有类型float, double, long double 的数字内容的s 的初始子字符串。p 的作用与整形转换函数中p 的作用相同。 |
字符串中我们能转换成数字的第一个非空格字符一定是可以在数字中出现的字符。
Code:
string s2 = "pi = 3.14";
// convert the first substring in s that starts with a digit, d = 3.14
d = stod(s2.substr(s2.find_first_of("+-.0123456789")));
上述代码中我们首先调用find_first_of
函数来找到字符串中第一个可以是数字的一部分的字符。我们将从find_first_of
返回位置处开始的子串传给stod
。stod
函数读取这个字符串直到遇到一个不能是数字的一部分的字符为止,然后将其转换为双精度的浮点数。
字符串中的第一个非空白字符必须是符号(+或 -)或数字。字符串可以以0x
或0X
开头,表示十六进制。对于转换为浮点的函数,字符串也可以以小数点(.)开头,并且可以包含e或E来指定指数。对于转换为整数类型的函数,根据基数,字符串可以包含与数字9之外的数字相对应的字母字符。
注:如果字符串无法转换为数字,则这些函数会抛出invalid_argument
异常。如果转换生成的值无法表示,则会抛出out_of_range
。
参考文献
[1] Lippman S B , Josée Lajoie, Moo B E . C++ Primer (5th Edition)[J]. 2013.