目录
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)
}