STL排序使用交换还是二进制拷贝?
Does STL sort use swap or binary copy?
我很难找到一个好的答案。出于某种原因,我认为STL排序应该使用swap来实现,以便更好地支持复杂类型,但是当我最终深入研究代码时,它似乎实际上是在进行二进制复制。有人能证实吗?我想二进制拷贝实际上比交换更可取。
附带问题:是否有STL算法或容器操作使用swap实现?(显然在std::swap
之外。)我想知道什么时候为复杂类型实现我自己的交换是谨慎的。
编辑:我问的原因是如果你有这样的东西:
class MyClass {
vector<int> vec_data;
int a;
int b;
}
vector<MyClass> my_vec;
sort(my_vec.begin(), my_vec.end(), MyCustomCompare);
我想确保排序没有调用vector的复制构造函数,如果调用MyData的默认复制构造函数,就会发生这种情况。因此,我的问题是排序调用交换,复制分配等?
不,c++标准库中的std::sort
不允许对具有非平凡复制/赋值操作符的对象进行二进制复制。我不明白为什么它不能用简单的复制/赋值操作符对对象进行二进制复制。考虑这个对象:
class Explosive {
Explosive* const self;
public:
Explosive() :self(this) {}
Explosive(const Explosive&) :self(this) {}
~Explosive() {assert(this==self);}
Explosive& operator=(const Explosive& rhs) {
assert(this==self && rhs.self==&rhs);
return *this;
}
bool operator<(const Explosive& rhs) const
{return std::less<Explosive*>(self,rhs.self);}
};
c++算法保证不触发任何断言,这意味着二进制拷贝将无效。
这取决于您的STL实现。GCC STL实现使用了内向排序和插入排序的组合。看来std::swap
(或您的专门化)将在内流排序循环中调用,但它不会被插入排序调用。
如果您没有std::swap
的专门化,那么默认的std::swap
实现将使用临时副本来实现交换。
它不使用二进制拷贝(除了一些POD类型,它们可能有隐藏在STL库深处的专门化)。
而且,在c++ 0x中,插入排序似乎可能会使用移动语义(右值引用)。
我以前看到过std::copy
在GNU libstdc++中使用memmove
,这取决于元素类型是否为POD has_trivial_assignment_operator
。请看这里的源代码:
template<typename _Tp>
inline _Tp*
__copy_trivial(const _Tp* __first, const _Tp* __last, _Tp* __result)
{
std::memmove(__result, __first, sizeof(_Tp) * (__last - __first));
return __result + (__last - __first);
}
至少在SGI中,rotate
, reverse
, swap_ranges
, random_shuffle
, partition
, next_permutation
都使用了swap
。
见http://www.sgi.com/tech/stl/stl_algo.h
此外,std::sort
的c++11标准文档在§25.4.1.1中特别提到:
要求:
RandomAccessIterator
应满足ValueSwappable
(17.6.3.2)的要求。*first
的类型应满足MoveConstructible
(表20)和MoveAssignable
的要求(表22)。
现在§17.6.3.2包含这个:
对象t可与对象u交换当且仅当:
- 表达式
swap(t, u)
和swap(u, t)
在下面描述的上下文中计算时是有效的,并且- 这些表达式有以下效果:
- t引用的对象具有最初由u和
持有的值- u所引用的对象具有最初由t持有的值。
计算
swap(t, u)
和swap(u, t)
的上下文应确保在候选集合上通过重载解析(13.3)选择名为" swap "的二进制非成员函数,该候选集合包括:
- (20.2)和
中定义的两个交换函数模板- 由参数相关查找(3.4.2)产生的查找集。
它会进行交换,但由于它是一个模板函数,因此它可能会内联交换代码。如果是简单类型,编译器可以选择进行二进制交换作为优化。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 有根的二进制搜索树.保留与其父级的链接
- 多态二进制函数
- 正在读取二进制文件(is_open)
- visual在c++中将十进制数转换为二进制数
- C++十进制到二进制,如何转换
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- 二进制搜索树叶数问题
- 如何将一个ostringstream十六进制字符串字符对转换为单个unit8t等价的二进制值
- 为什么二进制搜索在我的测试中不起作用
- 重载==不适用于二进制树
- 正在尝试重载二进制搜索树分配运算符
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 如何在没有数据拷贝的情况下从指针创建一个Eigen VectorXd对象
- 带有数组键C++的二进制映射
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 二进制数之和(使用C样式字符串)
- STL排序使用交换还是二进制拷贝?