C++容器之向量(std::vector)

1 概述

  矢量(vector)是序列容器,表示可以更改大小的数组。
  就像数组一样,向量为其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组中一样高效。但与数组(array)不同的是,它们的大小可以动态变化,其存储由容器自动处理。
  在内部,向量使用动态分配的数组来存储其元素。当插入新元素时,可能需要重新分配此数组以增加其大小,这意味着分配一个新数组并将所有元素移动到该数组。就处理时间而言,这是一项相对昂贵的任务,因此,每次向容器中添加元素时,矢量不是每次都重新分配。
  相反,矢量容器可以分配一些额外的存储空间来适应可能的增长,因此容器的实际容量可能大于容纳其元素所严格需要的存储空间(即其大小)。库可以实现不同的增长策略,以在内存使用和重新分配之间取得平衡,但在任何情况下,重新分配都只能以对数增长的大小间隔进行,这样在向量末尾插入单个元素就可以提供分摊的恒定时间复杂度(请参阅push_back)。
  因此,与数组(array)相比,矢量(vector)消耗更多的内存,以换取以高效方式管理存储和动态增长的能力。
  与其他动态序列容器(deques、list和forward_lists)相比,向量非常有效地访问其元素(就像数组一样),并且相对有效地从其末端添加或删除元素。对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他操作差,并且迭代器和引用的一致性不如list和forward_list。

其类图如下:
类图

2 使用实例

void VectorSuite::push_back()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::vector<int> a;
    std::vector<int> b;
    std::vector<int> c;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_back(array[i]);
    TEST_ASSERT_EQUALS(true, a.capacity() > a.size())

    
    b.reserve(ARRAY_SIZE(array));
    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        b.push_back(array[i]);
    TEST_ASSERT_EQUALS(true, b.capacity() == b.size())

    c.resize(ARRAY_SIZE(array));
    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        c[i] = array[i];
    TEST_ASSERT_EQUALS(true, c.capacity() == c.size())
}

3 接口使用

3.1 construct

std::vector<int> getVector(int size, int value)
{
    return std::vector<int>(size, value);
}
void VectorSuite::construct()
{
    std::vector<int> a;
    std::vector<int> b(4); // 0 0 0 0
    std::vector<int> c(4, 5);// 5 5 5 5
    std::vector<int> d({1, 2, 3, 4, 5});
    std::vector<int> e(d.begin(), d.end());
    std::vector<int> f(d);
    std::vector<int> g(getVector(6, 8));
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(4, b.size())
    TEST_ASSERT_EQUALS(4, c.size())
    TEST_ASSERT_EQUALS(5, d.size())
    TEST_ASSERT_EQUALS(5, e.size())
    TEST_ASSERT_EQUALS(5, f.size())
    TEST_ASSERT_EQUALS(6, g.size())
}

3.2 assigns

void VectorSuite::assigns()
{
    std::vector<int> a;
    std::vector<int> b;
    std::vector<int> c;
    a = { 1, 2, 3, 4, 5 };
    b = a;
    c = getVector(5, 10);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(5, c.size())
}

3.3 iterators

#define ARRAY_SIZE(array) sizeof(array) / sizeof(array[0])
void VectorSuite::iterators()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    int  rarray[] = { 5, 4, 3, 2, 1 };
    std::vector<int> a(array, array + ARRAY_SIZE(array));
    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }
    
    index = 0;
    for(auto it = a.cbegin(); it != a.cend(); ++it)
    {
        TEST_ASSERT_EQUALS(array[index++], *it)
    }

    index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index], *it)
        rarray[index] = rarray[index] * 2;
        *it = rarray[index++];
    }
    
    index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
    {
        TEST_ASSERT_EQUALS(rarray[index++], *it)
    }
}

3.4 capacity

void VectorSuite::capacity()
{
    std::vector<int> a;
    std::vector<int> b({1, 2, 3, 4, 5});
    TEST_ASSERT_EQUALS(0, a.size());
    TEST_ASSERT_EQUALS(5, b.size());
    TEST_ASSERT_EQUALS(true, a.empty());
    TEST_ASSERT_EQUALS(false, b.empty());

    TEST_ASSERT_EQUALS(a.max_size(), b.max_size());
    TEST_ASSERT_EQUALS(0, a.capacity());
    TEST_ASSERT_EQUALS(true, a.capacity() >= a.size());
    TEST_ASSERT_EQUALS(true, b.capacity() >= b.size()); // b.capacity() == b.size() == 5
}

说明:

  • 用初始化列表构造时,capacity与size是相等的。

3.5 rezize

void VectorSuite::rezize()
{
    std::vector<int> a;
    a.resize(5);

    std::cerr << "a.capacity=" << a.capacity() << std::endl;
    std::cerr << "a.size=" << a.size() << std::endl;
    TEST_ASSERT_EQUALS(5,  a.size());
    TEST_ASSERT_EQUALS(true, a.capacity() >= a.size());// a.capacity() == a.size() == 5
}

说明:

  • 调用resize后capacity与size是相等的。

3.6 reserve

void VectorSuite::reserve()
{
    std::vector<int> a;
    a.reserve(5);
    std::cerr << "a.capacity=" << a.capacity() << std::endl;
    std::cerr << "a.size=" << a.size() << std::endl;
    TEST_ASSERT_EQUALS(0,  a.size());
    TEST_ASSERT_EQUALS(true, a.capacity() > a.size());
}

说明:

  • 调用reserve后size不改变,capacity改变

3.7 shrink_to_fit

void VectorSuite::shrink_to_fit()
{
    std::vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4); //a.capacity() == a.size()
    a.push_back(5);
    TEST_ASSERT_EQUALS(true, a.capacity() > a.size());
    a.shrink_to_fit();
    TEST_ASSERT_EQUALS(true, a.capacity() == a.size());
}

说明:

  • 调用shrink_to_fit后capacity与size是相等的。

3.8 access

void VectorSuite::access()
{
    int  array[] = { 1, 2, 3, 4, 5 };
    std::vector<int> a(array, array + ARRAY_SIZE(array));
    

    TEST_ASSERT_EQUALS(1, a.front())//size of a must more than 0
    TEST_ASSERT_EQUALS(5, a.back()) //size of a must more than 0

    for(size_t i = 0; i < a.size(); i++)
    {
        TEST_ASSERT_EQUALS(array[i], a[i])
         array[i] = a[i] * 2;
        a[i] = array[i];
    }
    TEST_ASSERT_EQUALS(2, a.front())
    TEST_ASSERT_EQUALS(10, a.back())

    for(size_t i = 0; i < a.size(); i++)
    {
        TEST_ASSERT_EQUALS(array[i], a.at(i))
        array[i] = a.at(i) / 2;
        a.at(i) = array[i];
    }
    TEST_ASSERT_EQUALS(1, a.front())
    TEST_ASSERT_EQUALS(5, a.back())

    bool hasExcpetion = false;
    try {
        int v = a.at(6);
    }
    catch(...)
    {
        hasExcpetion = true;
    }
    TEST_ASSERT_EQUALS(true, hasExcpetion)
    int *d = a.data();
    for(int i = 0; i < ARRAY_SIZE(array); i++)
        TEST_ASSERT_EQUALS(array[i], d[i])
}

3.9 assign

void VectorSuite::assign()
{    
    std::vector<int> a;
    std::vector<int> b;
    std::vector<int> c;
    a.assign({ 1, 2, 3, 4, 5 });
    b.assign(a.begin(), a.end());
    c.assign(4, 5);

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(4, c.size())

    TEST_ASSERT_EQUALS(true, a.capacity() == a.size())
    TEST_ASSERT_EQUALS(true, b.capacity() == b.size())
    TEST_ASSERT_EQUALS(true, c.capacity() == c.size())
}

3.10 push_back

void VectorSuite::push_back()
{
    int array[] = { 1, 2, 3, 4, 5 };
    std::vector<int> a;
    std::vector<int> b;
    std::vector<int> c;

    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        a.push_back(array[i]);
    TEST_ASSERT_EQUALS(true, a.capacity() > a.size())

    
    b.reserve(ARRAY_SIZE(array));
    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        b.push_back(array[i]);
    TEST_ASSERT_EQUALS(true, b.capacity() == b.size())

    c.resize(ARRAY_SIZE(array));
    for(size_t i = 0; i < ARRAY_SIZE(array); i++)
        c[i] = array[i];
    TEST_ASSERT_EQUALS(true, c.capacity() == c.size())
}

3.11 pop_back

void VectorSuite::pop_back()
{
    std::vector<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(4, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(3, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(2, a.back())
    
    a.pop_back();
    TEST_ASSERT_EQUALS(1, a.back())

    a.pop_back();
    TEST_ASSERT_EQUALS(true, a.empty())

    if(!a.empty())
        a.pop_back();
    TEST_ASSERT_EQUALS(true, a.empty())
}

3.12 insert

void VectorSuite::insert()
{
    std::vector<std::string> names;
    std::string name("James");

    auto it = names.insert(names.begin(), name);//James
    TEST_ASSERT_EQUALS(name, *it)

    it = names.insert(names.end(), 2, "Tom"); //James Tom Tom 
    TEST_ASSERT_EQUALS("Tom", *it)

    it = names.insert(names.end(), "Peter"); //James Tom Tom Peter
    TEST_ASSERT_EQUALS("Peter", *it)

    it = names.insert(names.end(), {"Jim", "Rose", }); //James Tom Tom Peter Jim Rose
    TEST_ASSERT_EQUALS("Jim", *it)
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.13 erase

void VectorSuite::erase()
{
    std::vector<int> a({1, 2, 3, 4, 5});
    TEST_ASSERT_EQUALS(5, a.back())
    
    auto it = a.erase(a.begin() + 4);//1, 2, 3, 4

    //a.erase(a.begin() + 5); double free or corruption (out)

    TEST_ASSERT_EQUALS(true, it == a.end())
    TEST_ASSERT_EQUALS(4, a.back())

    it = a.erase(a.begin() + 1, a.begin() + 3);//1, 4
    TEST_ASSERT_EQUALS(4, *it)
    TEST_ASSERT_EQUALS(4, a.back())
}

说明:

  • 传入iterator必须是有效的
  • 返回iterator指向被删除元素的下一位置

3.14 swap

void VectorSuite::swap()
{
    std::vector<int> a({1, 2, 3, 4, 5});
    std::vector<int> b;

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(0, b.size())

    a.swap(b);
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
}

3.15 clear

void VectorSuite::clear()
{
    std::vector<int> a({1, 2, 3, 4, 5});

    TEST_ASSERT_EQUALS(5, a.size())
    a.clear();

    TEST_ASSERT_EQUALS(0, a.size())
}

3.16 emplace

void VectorSuite::emplace()
{
    std::vector<std::string> names;
    names.reserve(2);
    auto it = names.emplace(names.begin(), "james"); //james
    TEST_ASSERT_EQUALS("james", *it)
    it = names.emplace(names.end(), "jim"); //james jim
    TEST_ASSERT_EQUALS("jim", *it)
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.17 emplace_back

void VectorSuite::emplace_back()
{
    std::vector<std::string> names;
    names.reserve(2);
    names.emplace_back("james"); //james
    TEST_ASSERT_EQUALS("james", names.back())
    names.emplace_back("jim"); //james jim
    TEST_ASSERT_EQUALS("jim", names.back())
}

说明:

  • 返回iterator指向被删除元素的下一位置

3.18 get_allocator

void VectorSuite::get_allocator()
{
    std::vector<int> a;
    auto allocator = a.get_allocator();
    int* p = allocator.allocate(5);

    allocator.deallocate(p, 5);
    try
    {
        p = allocator.allocate(allocator.max_size() + 1);
    }
    catch(...)
    {
        p = nullptr;
    }
    TEST_ASSERT_EQUALS(true, p == nullptr)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值