标准库如何实现std :: swap?

在STL中如何实现交换function? 这是否简单:

template<typename T> void swap(T& t1, T& t2) { T tmp(t1); t1=t2; t2=tmp; } 

在其他职位,他们谈论专门为您自己的class级这个function。 为什么我需要这样做? 为什么我不能使用std::swap函数?

std::swap如何实现?

是的,在问题中提出的实现是经典的C ++ 03。

更现代的(C ++ 11) std::swap实现如下所示:

 template<typename T> void swap(T& t1, T& t2) { T temp = std::move(t1); // or T temp(std::move(t1)); t1 = std::move(t2); t2 = std::move(temp); } 

这是对资源pipe理方面的经典C ++ 03实现的一个改进,因为它可以防止不需要的副本等。它需要Ttypes为MoveConstructibleMoveAssignable ,因此允许实施和改进。

为什么我需要提供一个自定义的实现?

当您的实现比标准版本更高效或特定时,通常会build议针对特定types的swap的自定义实现。

一个典型的例子就是当你的class级pipe理大量的资源时,复制和删除将会很昂贵。 相反,您的自定义实现可以简单地交换实现交换所需的句柄或指针。

随着std::move和可移动types(以及types的实现)的出现,大约C ++ 11以及之后,这里的很多原始原理开始消失; 但是,如果定制互换会比标准互换更好,那就执行它。

通用代码通常能够使用您的自定义swap如果它适当地使用ADL机制。

在STL中如何实现交换function?

哪个实现? 这是一个规范,而不是一个具体的库。 如果你的意思是我的编译器的标准库怎么做的,那就告诉我们是哪个编译器,或者自己读取代码。

这是否简单:

这实质上是pre-C ++ 11的天真版本。

这个非专门的实现强制一个副本:在你的例子中T = std::vector<SomethingExpensive> ,代码翻译为:

 template<typename T> void swap(T& t1, T& t2) { T tmp(t1); // duplicate t1, making an expensive copy of each element t1=t2; // discard the original contents of t1, // and replace them with an expensive duplicate of t2 t2=tmp; // discard the original contents of t2, // and replace them with an expensive duplicate of tmp } // implicitly destroy the expensive temporary copy of t1 

所以交换两个向量我们基本上创造了三个 。 有三个dynamic分配和大量的昂贵的对象复制,任何这些操作可能会抛出,可能使参数处于不确定的状态。

由于这显然很糟糕,所以为昂贵的容器提供了过载,并鼓励您为自己昂贵的types写入过载。 std::vector专门化可以访问vector的内部,并且可以交换两个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 } 

请注意,这涉及到任何昂贵的副本,没有dynamic(德)分配,并保证不抛出。

现在,这个专业化的原因是vector :: swap可以访问vector的内部元素,并且可以安全而高效地移动它们而不需要复制。

为什么我需要做这个[专门…为你自己的class级]?

Pre-C ++ 11,与std::vector相同的原因,使交换高效和exception安全。

由于C ++ 11,你真的不这样做 – 如果你提供移动构造和赋值,或者编译器可以为你生成默认值。

新的通用交换:

 template <typename T> void swap(T& t1, T& t2) { T temp = std::move(t1); t1 = std::move(t2); t2 = std::move(temp); } 

可以使用移动构造/赋值来实现与上述自定义向量实现基本相同的行为,而不需要编写自定义实现。