vector
1.noexcept使用
当 push_back、 insert、 reserve、 resize 等函数导致内存重分配时,或当 insert、 erase 导致元素位置移动时, vector 会试图把元素“移动”到新的内存区域。 vector 通常保证强异常安全性,如果元素类型没有提供一个 保证不抛异常的移动构造函数, vector 通常会使用拷贝构造函数。因此,对于拷贝代价较高的自定义元素类型,我们应当定义移动构造函数,并标其为 noexcept
#include <iostream>
#include <vector>
using namespace std;
class Obj1 {
public:
Obj1()
{
cout << "Obj1()\n";
}
Obj1(const Obj1&)
{
cout << "Obj1(const Obj1&)\n";
}
Obj1(Obj1&&)
{
cout << "Obj1(Obj1&&)\n";
}
};
class Obj2 {
public:
Obj2()
{
cout << "Obj2()\n";
}
Obj2(const Obj2&)
{
cout << "Obj2(const Obj2&)\n";
}
Obj2(Obj2&&) noexcept
{
cout << "Obj2(Obj2&&)\n";
}
};
int main()
{
vector<Obj1> v1;
v1.reserve(2);
v1.emplace_back();
v1.emplace_back();
v1.emplace_back();
vector<Obj2> v2;
v2.reserve(2);
v2.emplace_back();
v2.emplace_back();
v2.emplace_back();
}
`Obj1()`
`Obj1()`
`Obj1()`
`Obj1(const Obj1&)`
`Obj1(const Obj1&)`
`Obj2()`
`Obj2()`
`Obj2()`
`Obj2(Obj2&&)`
`Obj2(Obj2&&)`
Obj1和Obj2的定义只差了一个noexcept,但这个小小的差异就导致了 vector` 是否会移动对象。这点非常重要。
2.vector的emplace和push_back
push_back会额外产生临时对象,多一次(移动/拷贝)构造和析构。如果是移动的情况,会有小幅性能损失。如果对象没有实现移动的话,性能差异就可能比较大了。
queue双端队列
queue特点
- 如果只从头、尾两个位置对
deque进行增删操作的话,容器里的对象永远不需要移动。 - 容器里的元素只是部分连续的(因而没法提供
data成员函数)。 - 由于元素的存储大部分仍然连续,它的遍历性能是比较高的。
- 由于每一段存储大小相等,
deque支持使用下标访问容器元素,大致相当于index[i / chunk_size][i % chunk_size],也保持高效。