使用大对象时的STL效率

时间:2015-08-17 19:04:56

标签: c++ c++11 stl

更具体地说,让我们将问题的范围限制为libstdc ++和Visual C ++。

考虑存储在容器中的对象具有以下属性的情况:

  • 复制和分配可能很昂贵
  • 移动和交换便宜且永不丢弃
  • 默认构造函数很便宜且永不抛出

添加或删除元素时,某些容器可能会重新分配/移动存储的对象。在这种情况下,上面提到的STL实现是否避免在重新分配/移动元素时进行复制?

std :: sort 和其他算法怎么样?

如果您考虑一下,移动和交换时无需复制。

您可能知道所有STL操作都提供 Big O 复杂性保证。 B ig O 表示常数乘以 N 的某个函数。我的问题可以通过询问常数包括什么来解释?它是否包括复制成本或者与移动/交换成本成比例?

谢谢你。

1 个答案:

答案 0 :(得分:1)

唯一可以给出的一般答案是C ++是由关心性能的聪明人制作的,所以你通常不会发现错过了很容易的优化,也不应该过分担心你的标准图书馆的表现。

您可以通过阅读标准,cppreference.com等网站或您的实施附带的文档中的规范,逐个类型和逐个功能地回答这些问题。例如,如果std::vector::push_back必须重新分配其内部缓冲区,它将使用移动构造函数“复制”元素,当且仅当此类构造函数存在且声明为noexcept时(另请参阅{ {3}})。

对标准库中实际的内容进行推理的另一种方法是将其用于测试驱动器。使用简单的struct来打印来自其构造函数和赋值运算符的日志消息,然后将该类的实例放入标准库容器中并对其执行一些算法。以下示例使用std::vectorstd::sort。您可以使用不同的容器和算法来玩它。如果您进行了评论所指示的更改,也请查看发生了什么。

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>


struct Example
{

  int id;

  Example(const int id) : id {id}
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Example(const Example& rhs) : id {rhs.id}
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  // try commenting out the 'noexcept'
  Example(Example&& rhs) noexcept : id {rhs.id}
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Example&
  operator=(const Example& rhs)
  {
    this->id = rhs.id;
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return *this;
  }

  // try commenting out the 'noexcept'
  Example&
  operator=(Example&& rhs) noexcept
  {
    this->id = rhs.id;
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return *this;
  }

  ~Example() noexcept
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

};


int
main()
{
  const auto n = 10;
  auto rndeng = std::default_random_engine {};
  auto rnddst = std::uniform_int_distribution<int> {};
  auto elements = std::vector<Example> {};
  std::cout << "CONSTRUCTING VECTOR OF " << n << " ELEMENTS...\n\n";
  elements.reserve(n);  // try commenting this out
  for (auto i = 0; i < n; ++i)
    elements.emplace_back(rnddst(rndeng));  // try using push_back instead
  const auto cmp = [](const Example& lhs, const Example& rhs){
    return lhs.id < rhs.id;
  };
  std::cout << "\nSORTING ELEMENTS...\n\n";
  std::sort(elements.begin(), elements.end(), cmp);
  std::cout << "\nSORTED ELEMENTS:\n\n";
  for (const auto& elem : elements)
    std::cout << std::setw(16) << elem.id << "\n";
  std::cout << "\nLEAVING MAIN...\n\n";
}