在 STL 已提供std::swap
时为什么还有必要使用 boost::swap
?
std::swap
的行为等效于:
template <class T> void swap ( T& a, T& b ) { T c(a); a=b; b=c; } |
现在,对于存储大量数据的类,此方法可能不是交换数据的最有效方法,因为 swap
涉及到一个 copy construction
和两次赋值。另外,对于出于设计原因拥有 private 构造函数而没有复制构造函数的类,所以这种交换风格不适用。以下是 boost::swap
提供的功能:
- 您可以交换
T
类型的数组,而std::swap
不能。 boost::swap
可调用具有签名swap(T&, T&)
的函数,只要存在相同的签名,且不存在默认的copy constructor
及两个赋值选项。boost::swap
可调用std::swap
的一个特殊化模板。- 如果上面第二和第三个选项都是有效选项,
T
必须是可构造和可赋值的副本。
清单 19 给出了用于交换两个数组的 boost::swap
。
清单 19. 使用 boost::swap 交换两个数组
#include <boost/swap.hpp> #include <boost/foreach.hpp> #include <iostream> using namespace std; int main() { int a[] = {10, 20, 30, 40}; int b[] = {4, 3, 2, 1}; boost::swap(a, b); // using std::swap here won't work BOOST_FOREACH(int t, a) { cout << t << endl; } BOOST_FOREACH(int t, a) { cout << t << endl; } } |
boost::swap
调用您的自定义交换例程的示例如 清单 20 中所示。
清单 20. 使用 boost::swap 实现自定义交换
#include <boost/swap.hpp> #include <iostream> using namespace std; typedef struct T { int m_data; T(int data) : m_data(data) { } } T; void swap(T& a, T& b) // custom swap routine that boost ::swap calls { cout << "In custom swap" << endl; a.m_data ^= b.m_data; b.m_data ^= a.m_data; a.m_data ^= b.m_data; } int main() { T a(30), b(10); boost::swap(a, b); cout << a.m_data << endl; cout << b.m_data << endl; } |
最后,模板特殊化的版本如 清单 21 中所示。
清单 21. 使用 std::swap 的模板特殊化版本
#include <boost/swap.hpp> #include <iostream> using namespace std; typedef struct T { int m_data; T(int data) : m_data(data) { } } T; namespace std { template< void swap<T> (T& a, T& b) { cout << "In template-specialized swap" << endl; a.m_data ^= b.m_data; b.m_data ^= a.m_data; a.m_data ^= b.m_data; } } int main() { T a(30), b(10); boost::swap(a, b); cout << a.m_data << endl; cout << b.m_data << endl; } |
现在,让我们看看实现 boost::swap
的内部原理。我们感兴趣的是如何定义 swap...for
数组。清单 22 给出了代码,它从 boost/swap.hpp 复制而来。
清单 22. boost::swap 的源代码
#include <algorithm> //for std::swap #include <cstddef> //for std::size_t namespace boost_swap_impl { template<class T> void swap_impl(T& left, T& right) { using namespace std;//use std::swap if argument dependent lookup fails swap(left,right); } template<class T, std::size_t N> void swap_impl(T (& left)[N], T (& right)[N]) { for (std::size_t i = 0; i < N; ++i) { ::boost_swap_impl::swap_impl(left[i], right[i]); } } } namespace boost { template<class T1, class T2> void swap(T1& left, T2& right) { ::boost_swap_impl::swap_impl(left, right); } } |
对于数组,调用 boost::swap
最终会导致调用 void swap_impl(T (& left)[N], T (& right)[N])
,因为后者也已针对数组进行了特殊化处理。查看声明 swap_impl(T (& left)[N], T (& right)[N])
,这里left
和 right
是具有类型 T
和大小 N
的数组的引用。两个数组必须具有相同的大小,否则您会获得编译错误消息。
对于所有其他情形,会调用 swap_impl(T& left, T& right)
。查看 swap_impl(T& left, T& right)
的定义,您会看到它调用了 swap
例程。如果您拥有自己的模板特殊化的 std::swap
版本(请参见 清单 21)或全局 swap
例程(请参见 清单 20),将调用相同例程。否则,将调用 std::swap
。
如果 boost::swap
和 std::swap
位于相同范围内,那么对 swap
的调用将优先于 std::swap
。