C++容器注意

137 阅读1分钟

vector

image.png

1.noexcept使用

push_backinsertreserveresize 等函数导致内存重分配时,或当 inserterase 导致元素位置移动时, 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&&)`

Obj1Obj2的定义只差了一个noexcept,但这个小小的差异就导致了 vector` 是否会移动对象。这点非常重要。

2.vector的emplace和push_back

push_back会额外产生临时对象,多一次(移动/拷贝)构造和析构。如果是移动的情况,会有小幅性能损失。如果对象没有实现移动的话,性能差异就可能比较大了。

queue双端队列

image.png

queue特点

  • 如果只从头、尾两个位置对 deque 进行增删操作的话,容器里的对象永远不需要移动。
  • 容器里的元素只是部分连续的(因而没法提供 data 成员函数)。
  • 由于元素的存储大部分仍然连续,它的遍历性能是比较高的。
  • 由于每一段存储大小相等, deque 支持使用下标访问容器元素,大致相当于 index[i / chunk_size][i % chunk_size],也保持高效。