新普京网站-澳门新普京 > 前端 > 新特性之容器相关特性

新特性之容器相关特性

2019/12/29 22:31

那是C++11新特性介绍的第四片段,涉及到C++11此次更新中与容器有关的新特色。

不想看toy code的读者能够平昔拉到文章最后看那部分的总计。

cbegin和cend

原先的begin和end重返的iterator是还是不是是常量决定于对应的容器类型,但是一时,固然容器不是常量类型,大家也盼望获得二个const_iterator,以免止不供给的更正行为。C++11新职业中提供了cbegin和cend函数,无论容器类型,都固定重返const_iterator。

vector<int> c1 = {0, 1, 2, 3, 4};
auto it1_1 = c1.begin();
auto it1_2 = c1.cbegin();
*it1_1 = 4;
//*it1_2 = 5; // wrong, const iterator's value can't be changed via this iterator.
cout<<*it1_1<<'t'<<*it1_2<<endl;

标准库的begin和end

C++11新专门的学业提供了begin和end函数,能够对日常性数组使用,拿到头指针和尾指针。

int c2[] = {0, 1, 2, 3, 4};
auto it2_1 = begin(c2);
auto it2_2 = end(c2);
while(it2_1 != it2_2)
{
    cout<<*it2_1<<'t';
    it2_1++;
}
cout<<endl;

新的赋值方式

C++11允许使用三个{}包围的初始值列表来实行理并答复制。若是等号左边是个容器,那么怎么赋值由容器决定。

vector<int> c3;
c3 = {0, 1, 2, 3, 4};
for(auto it3_1 = c3.begin(); it3_1 != c3.end(); it3_1++)
    cout<<*it3_1<<'t';
cout<<endl;

initializer_list

C++11新专门的职业中新增了initializer_list类型,其实在头里介绍初始化的那篇作品中,使用vector v = {0, 1, 2, 3, 4}这种开端化方式时,就隐式的使用了initializer_list:每当在前后相继中冒出朝气蓬勃段以{}包围的字面量时,就能够自行构造叁个initializer_澳门新普京 ,list对象。

另外,initializer_新普京网站 ,list的另一个功力就在于作为函数的形参,那样的函数能够实惠的无胫而行以{}包围的不定长列表:

void print_list(initializer_list<int> il)
{
    for(auto it = il.begin(); it != il.end(); it++)
    {
        cout<<*it<<'t';
        //*it = 100; // wrong. initializer_list element is read-only.
    }
    cout<<endl;
}

print_list({0, 1, 2, 3, 4});
print_list({0, 1, 2, 3, 4, 5});

只是,必要留意的是,initializer_list中的成分是只读的。

array

C++11正规中提供了定长数组容器array,比较于常常数组更安全、更易使用。array是定长数组,所以不帮助诸如插入、删除等转移容器大小的操作,不过足以对成分举行赋值退换其值。

array<int, 5> c4 = {0, 1, 2, 3, 4};
c4[3] = 100; // can't insert since the array size is fixed.
for(auto it4_1 = c4.begin(); it4_1 != c4.end(); it4_1++)
{
    cout<<*it4_1<<'t';
}
cout<<endl;

forward_list

C++11正式中追加了新的容器forward_list,提供了多个快速的、安全的单向链表达成。因为是单向链表,所以也就未有rbegin、rend风流罗曼蒂克类的函数协理了。

相仿是因为单向链表的缘故,不能够访谈到给定元素的先行者,所以没有提供insert函数,而相应提供了七个insert_after函数,用于在给定元素之后插入节点。erase_after、emplace_after同理。

forward_list<int> c5 = {3, 4};
c5.push_front(2);
c5.push_front(1);
auto it5_1 = c5.before_begin();
c5.insert_after(it5_1, 0);
for(auto it5_2 = c5.begin(); it5_2 != c5.end(); it5_2++)
{
    cout<<*it5_2<<'t';
}
cout<<endl;

swap

新标准中提供了非成员版本的swap操作,此操作对array容器,会换成成分的值;对其余容器,则只调换容器的内部构造,并不开展成分值的正片操作,所以在这里种情况下是老大赶快的。

正因如此,当swap array后,原本array上的迭代器还依然指向原有成分,只是元素的值变了;
而swap非array容器之后,原本容器上的迭代器将针对对方容器上的要素,而针没有错要素的值却保持不改变。

vector<int> c6 = {0, 1, 2, 3, 4};
vector<int> c7 = {5, 6, 7, 8, 9};
auto it6_1 = c6.begin();
auto it7_1 = c7.begin();
swap(c6, c7);
for(auto it6_2 = c6.begin(); it6_2 != c6.end(); it6_2++)
    cout<<*it6_2<<'t';
cout<<endl;

for(auto it7_2 = c7.begin(); it7_2 != c7.end(); it7_2++)
    cout<<*it7_2<<'t';
cout<<endl;

cout<<(it6_1 == c7.begin())<<'t'<<(it7_1 == c6.begin())<<endl;

array<int, 5> c8 = {0, 1, 2, 3, 4};
array<int, 5> c9 = {5, 6, 7, 8, 9};
auto it8_1 = c8.begin();
auto it9_1 = c9.begin();
swap(c8, c9);
cout<<(it8_1 == c8.begin())<<'t'<<(it9_1 == c9.begin())<<endl;

emplace

emplace操作将采用选择的参数布局二个应和容器中的成分,并插入容器中。这点,使用普通的insert、push操作是做不到的。

class TestData
{
    public:
        TestData(string name, int age, double salary): name(name), age(age), salary(salary)
        {}
    private:
        string name;
        int age;
        double salary;
};

vector<TestData> c10;
c10.emplace_back("yubo", 26, 100000000000.0);
//c10.push_back("laowang", 56, 10.5); // wrong. no 3 params push_back
c10.push_back(TestData("laowang", 56, 10.5));
cout<<c10.size()<<endl;

shrink_to_fit

雷同可变长容器会预先多分配风流洒脱部分内部存款和储蓄器出来,以备在持续增比索素时,不用每一次都报名内部存款和储蓄器。所以有size和capacity之分。size是近年来容器中存有成分的个数,而capacity则是在不重复申请内部存款和储蓄器的场所下,当前可存放元素的最大数额。而shrink_to_fit就意味着将capacity中的多余部分退回,使其重临size大小。然则,这一个函数的切切实实作用要信任于编写翻译器的兑现……

vector<int> c11;
for(int i = 0; i < 24; i++)
    c11.push_back(i);
cout<<c11.size()<<'t'<<c11.capacity()<<endl;
c11.shrink_to_fit();
cout<<c11.size()<<'t'<<c11.capacity()<<endl;

严节关联容器

C++11新标准中引进了对map、set等事关容器的冬天版本,叫做unorderer_map/unordered_set。

冬季关联容器不采取键值的比较操作来组织成分顺序,而是利用哈希。那样在一些因素顺序不重要的情况下,成效更加高。

unordered_map<string, int> c12;
map<string, int> c13;
string string_keys[5] = {"aaa", "bbb", "ccc", "ddd", "eee"};
for(int i = 0; i < 5; i++)
{
    c12[string_keys[i]] = i;
    c13[string_keys[i]] = i;
}
cout<<"normal map:n";
for(auto it13 = c13.begin(); it13 != c13.end(); it13++)
    cout<<it13->first<<':'<<it13->second<<'t';
cout<<endl;
cout<<"unordered map:n";
for(auto it12 = c12.begin(); it12 != c12.end(); it12++)
    cout<<it12->first<<':'<<it12->second<<'t';
cout<<endl;

tuple

熟悉python的程序员相应对tuple都不不熟悉,C++1第11中学也引入了那生机勃勃数据布局,用于方便的将区别类其他值组合起来。

能够由此如下方式,获取tuple中的元素、tuple的尺寸等:

//tuple<int, string, vector<int>> c14 = {1, "tuple", {0, 1, 2, 3, 4}}; // wrong. must explicit initialize
tuple<int, string, vector<int>> c14{1, "tuple", {0, 1, 2, 3, 4}};
get<0>(c14) = 2;
typedef decltype(c14) ctype;
size_t sz = tuple_size<ctype>::value;
cout<<get<0>(c14)<<'t'<<get<1>(c14)<<'t'<<get<2>(c14)[0]<<'t'<<sz<<endl;

总结

  1. cbegin和cend提供了定位获取const_iterator的方式。
  2. begin和end用于普通数组得到首尾指针。
  3. 能够运用{}包围的初叶值列表实行赋值。
  4. 增加initializer_list类型用于方便的选拔{}包围的不定长列表。
  5. 充实新的定长数组容器array 单向链表容器forward_list。
  6. 充实非成员函数版本的swap操作。对array swap只调换到分值,而容器的结构不改变;对其余容器则只更改容器数据布局,而要素值不改变。
  7. 日增emplace操功用于将参数传递给布局函数布局成分并插入容器。
  8. 增加shrink_to_fit函数用于退回多余的空间。
  9. 充实九冬关联容器。
  10. 增加tuple容器。

黄金时代体化代码详见container.cpp

上一篇:编程风格指南,里的继承和多态 下一篇:没有了