使用大对象时的STL效率
STL efficiency when using big objects
更具体地说,让我们将问题的范围限制在libstdc++和Visual c++。
考虑存储在容器中的对象具有以下属性的情况:
- 复制和赋值可能很昂贵
- 移动和交换是便宜的,永远不会抛出
- 默认构造函数是便宜的,从不抛出
当添加或删除元素时,一些容器可能会重新分配/移动存储的对象。在这种情况下,上面提到的STL实现在重新分配/移动元素时避免复制吗?
那么std::sort和其他算法呢?
如果你仔细想想,当移动和交换可用时,就不需要复制了。
你可能知道所有STL操作都提供大O复杂性保证。Big O表示有一个常数乘以N的某个函数。我的问题可以改写成这个常数包括什么?它是否包括复制的成本,还是与移动/交换的成本成比例?
谢谢你。
唯一可以给出的一般答案是c++是由非常关心性能的聪明人开发的,所以你通常不会发现容易的优化错过了,也不应该太担心你的标准库的性能。
您可以通过阅读标准中的规范、cppreference.com等网站或随您的实现附带的文档来逐一回答这些问题。例如,如果std::vector::push_back
必须重新分配其内部缓冲区,它将使用move构造函数来"复制"元素,当且仅当该构造函数存在并且声明为noexcept
(参见std::move_if_noexcept
)。
struct
来打印来自其构造函数和赋值操作符的日志消息,然后将该类的实例放入标准库容器中,并在其上执行一些算法。下面以std::vector
和std::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...nn";
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...nn";
std::sort(elements.begin(), elements.end(), cmp);
std::cout << "nSORTED ELEMENTS:nn";
for (const auto& elem : elements)
std::cout << std::setw(16) << elem.id << "n";
std::cout << "nLEAVING MAIN...nn";
}
相关文章:
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 在C应用程序中运行C++(带有STL)函数
- 使用2个键的cpp-stl::优先级队列排序不正确
- 在STL容器中使用模板类
- 为什么当我解模块化时,这个C++代代码"效率较低"?
- 用C++中的CPerson(类)类型的对象初始化STL矢量
- 将stl字符串缩小到小于15个字符的容量
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查函数返回类型是否与STL容器类型值相同
- STL算法函数在多个一维容器上的使用
- STL/标准C++容器的最佳效率如何
- stl数据结构的堆栈上输出参数与返回值的效率
- 迭代器和const_iterator的效率不同(STL)
- 每个C++STL收集操作的算法效率
- 使用大对象时的STL效率
- STL矢量元素去除效率
- 固定大小数组的STL算法效率
- 基于函数返回的stl容器的构造效率
- STL 映射插入效率:[] 与插入