您的位置:首页 > 其它

boost::swap 的实现原理

2014-03-12 10:38 183 查看
在 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)
, T (& right)
)
{
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)
, T (& right)
)
,因为后者也已针对数组进行了特殊化处理。查看声明 
swap_impl(T (& left)
, T (& right)
)
,这里
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


原链接:http://www.oschina.net/question/129540_32439
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: