STL中的交换函数是如何实现的?
哪一种实现?它是一个规范,不是一个具体的库。如果你想知道我的编译器标准库是如何实现的,要么告诉我们你使用的是哪个编译器,要么自己阅读代码。
它就是这么简单吗?
这本质上是C++11之前的朴素版本。
这个未特化的实现强制进行了复制:对于你的例子中的
T = std::vector<SomethingExpensive>
,代码转换为:
template<typename T> void swap(T& t1, T& t2) {
T tmp(t1);
t1=t2;
t2=tmp;
}
为了交换两个向量,我们实际上创建了三个向量。这里涉及到了三个动态分配以及大量昂贵的对象复制,而且任何一个操作都可能抛出异常,可能会使参数处于不确定状态。
由于这显然是糟糕的,因此为昂贵的容器提供了重载,并鼓励您为自己的昂贵类型编写重载:例如,std::vector
专业化可以访问向量的内部,可以在不进行所有复制的情况下交换两个向量:
template <typename T> void swap(vector<T> &v1, vector<T> &v2) { v1.swap(v2); }
template <typename T> void vector<T>::swap(vector<T>& other) {
swap(this->size_, other.size_); // cheap integer swap of allocated count
swap(this->used_, other.used_); // cheap integer swap of used count
swap(this->data__, other.data_); // cheap pointer swap of data ptr
}
请注意,这不涉及任何昂贵的复制,没有动态分配内存,且保证不会抛出异常。
现在,为什么要进行这种特殊化呢?因为vector::swap可以访问vector的内部,并安全有效地移动它们,而无需复制。
那么,“为什么需要为自己的类进行这种特化呢?”在C++11之前,出于与std::vector相同的原因——使交换高效和异常安全。但是,如果您提供了移动构造和赋值,或者编译器可以为您生成合理的默认值,则实际上不需要这样做。
新的通用交换:
template <typename T> void swap(T& t1, T& t2) {
T temp = std::move(t1);
t1 = std::move(t2);
t2 = std::move(temp);
}
可以使用移动构造/赋值来获得与上述自定义向量实现本质相同的行为,而无需编写自定义实现。
std::swap
的方式,而在C++11中,使用T tmp(std::move(t1)); t1 = std::move(t2); t2 = std::move(tmp);
会比一些类型的拷贝更有效率。 - Jonathan Wakely