C++11——顺序容器

2019-04-24  本文已影响0人  铭小汁儿

forward_list和array容器

新标准添加了forward_listarray容器。array容器是内置数组的一种更安全更易于使用的替代方法。与内置数组一样,标准库提供的array容器有固定大小。因此array容器不支持添加和删除元素或调整容器大小的操作。forward_list容器是具有最佳性能的手写单链表的替代。因此forward_list容器不支持size操作,因为与最佳性能的手写单列表相比,存储或计算其大小会产生开销。对于标准库中其他容器,size操作保证是快速,常量时间操作。
新的标准库容器比以前的版本快得多。可以肯定的是标准库容器通常表现得比最精心设计的替代品要好。现代C ++程序应该使用标准库容器而不是像数组这样的更原始的结构。
关于array容器更详细的信息可参考header <array>
关于forward_list容器更详细的信息可参考header <forward_list>

容器的cbegin和cend函数

新标准中引入了容器的cbegincend函数,用于返回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

autobeginend一起使用时,我们得到的迭代器类型取决于容器类型。而使用cbegincend时无论容器的类型如何都会得到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_frontemplaceemplace_back,并且它们执行时是构造而不是复制元素。这些操作对应于push_frontinsertpush_back操作,因为它们允许我们将元素分别放在容器的前面,给定位置的前面或容器的后面。
当我们调用pushinsert成员时,我们传递元素类型的对象,并将这些对象复制到容器中。当我们调用一个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来请求dequevectorstring返回不需要的内存。 此功能表明我们不再需要任何多余的容量。我们无法保证调用shrink_to_fit将返回内存。
shrink_to_fit仅仅对dequevectorstring有效;capacityreserve仅仅对vectorstring有效。

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返回位置处开始的子串传给stodstod函数读取这个字符串直到遇到一个不能是数字的一部分的字符为止,然后将其转换为双精度的浮点数。
字符串中的第一个非空白字符必须是符号(+或 -)或数字。字符串可以以0x0X开头,表示十六进制。对于转换为浮点的函数,字符串也可以以小数点(.)开头,并且可以包含e或E来指定指数。对于转换为整数类型的函数,根据基数,字符串可以包含与数字9之外的数字相对应的字母字符。
注:如果字符串无法转换为数字,则这些函数会抛出invalid_argument异常。如果转换生成的值无法表示,则会抛出out_of_range

参考文献

[1] Lippman S B , Josée Lajoie, Moo B E . C++ Primer (5th Edition)[J]. 2013.

上一篇下一篇

猜你喜欢

热点阅读