Boost Development Guide-4.5swap

swap

boost::swap is an enhancement and generalization of std::swap in the standard library. It provides a convenient method for exchanging the values ​​of two variables (which can be built-in data types such as int, or class instances or containers).

In order to use boost::swap, the header file <boost/swap.hpp> needs to be included, that is

#include<boost/swap.hpp>

principle

std::swap() in the C++98 standard

template<typename T>
void swap(T&a, T& b)
{
    
    
    T tmp(a);
    a = b;
    b = temp;
}

As can be seen from the code, std::swap() requires that the exchanged object must be copy-constructible and copy-assignable. It provides the most versatile and least efficient method, requiring one copy construction and two assignments. The operation can be quite expensive if the objects being exchanged are large.

The C++11 standard uses transfer semantics to optimize std::swap() to avoid the cost of copying.

template<typename T>
void swap(T& a, T& b)
{
    
    
     T tmp = std::move(a); //move, 把a偷到tmp
     a = std::move(b); //move, 把b偷到a
     b = std::move(tmp); //move, 把tmp偷到b
}

But not all classes implement their own transfer constructs and assignment functions, and compiler support is also an issue that must be considered. Therefore, for classes we write ourselves, it is best to implement optimized swap() to improve efficiency.

There are two solutions: the first solution is to directly use function overloading and write a swap_ function with the same name. This swap() then calls the efficient member exchange function inside the class, so that the compiler will not use std during compilation. ::swap(). The second option is to use ADrR to find the template specialization of std::swap. These two solutions are how boost::swap works.

boost::swap searches for a specialization of std::swap() of type T or searches for a template-specialized swap() through ADL. If so, it calls it. If both searches fail, it degrades to std:: swap(). In addition, boost::swap also adds a very practical feature - support for C++'s built-in array exchange (has been included in the C++11 standard).

The declaration of the boost::swap() function is:

template<class T1, class T2>
void swap(T1& left, T2& right);

Since boost::swap() has the same name as std::swap(), we cannot use the using statement to open the boost namespace. We should always call it in a boost namespace-qualified manner.

Swapping arrays

boost::swap can directly exchange the contents of two arrays, but the two arrays participating in the exchange must have the same length. The following code uses the standard library algorithm fill_n to assign the two arrays to 5 and 20 respectively, and then calls boost::swap() to swap:

int a1[10]; //两个数组
int a2[10];

std::fill_n(a1, 10, 5); //fill_n赋初始值
std::fill_n(a2, 10, 20);

boost::swap(a1, a2); //交换两个数组的内容

The implementation of boost::swap to exchange the contents of an array is very simple. It uses a for loop to call a single element version of boost::swap for each element in the array to complete the exchange of the entire array contents. After the above code is executed, the value of the element in a1 will be 20, and the value of the element in a2 will be 5.

If you try to use boost::swap to swap two arrays of different lengths, it will not compile:

int a1[10], a2[12]; //两个长度不相同的数组
boost::swap(a1, a2); //发生编译错误

specialized std::swap

Next, we use a simple point in three-dimensional space as an example to demonstrate the template specialization method using boost::swap. It implements an internal efficient exchange function:

class point
{
    
    
	int x, y, z;
public:
	explicit point(int a = 0, int b = 0, int c = 0) :x(a), y(b), z(c) {
    
    }

	void print()const
	{
    
    
		cout << x << "," << y << "," << z << endl;
	}

	void swap(point& p) //内置高效交换函数
	{
    
    
		std::swap(x, p.x);
		std::swap(y, p.y);
		std::swap(z, p.z);
		cout << "inner swap" << endl;
	}
};

Specializing std::swap() requires adding a custom function to the std namespace:

namespace std
{
    
    
   template<>
   void swap(point &x, point &y)
   {
    
     x.swap(y); }
}

int main()
{
    
    
    point a(1,2,3), b(4,5,6);
    cout << "std::swap" << endl;
    std::swap(a,b); //调用std::swap
    cout << "boost::swap" << endl;
    boost::swap(a, b); //调用boost::swap
}

Since we have specialized std::swap in the namespace, boost::swap has the same effect as std::swap, both using the specialized swap function.

Specialize ADL findable swap

Still using the point class just now, but this time we do not change the std namespace, but implement the swap function in the global domain:

void swap(point &x, point &y) //全局域的swap函数
{
    
     x.swap(y); }

int main()
{
    
    
    point a(1,2,3), b(4,5,6);
    
    cout << "std::swap" << endl;
    std::swap(a,b); //调用std::swap

    cout << "boost::swap" << endl;
    boost::swap(a,b); //调用boost::swap
}

The running result of this code is significantly different from the previous specialization of std::swap. std::swap uses standard exchange operations, while boost::swap finds the specialized exchange function of the global namespace through ADL rules and implements for efficient exchange.

If readers are worried that writing a free function swap in the global namespace will cause name "pollution", they can add the specialized swap to the boost namespace, or other namespaces that ADL can find.

code example

#include <iostream>
using namespace std;

#include <boost/core/swap.hpp>
#include <boost/assign.hpp>

//
void case1()
{
    
    
	using namespace boost::assign;

	int a1[10];
	int a2[10];

	std::fill_n(a1, 10, 5);
	std::fill_n(a2, 10, 20);

	boost::swap(a1, a2);

}

//
class point
{
    
    
	int x, y, z;
public:
	explicit point(int a = 0, int b = 0, int c = 0) :x(a), y(b), z(c) {
    
    }

	void print()const
	{
    
    
		cout << x << "," << y << "," << z << endl;
	}

	void swap(point& p)
	{
    
    
		std::swap(x, p.x);
		std::swap(y, p.y);
		std::swap(z, p.z);
		cout << "inner swap" << endl;
	}
};

//namespace std
//{
    
    
//template<>
//void swap(point &x, point &y)               //模板特化swap函数
//{   x.swap(y);}
//}

namespace boost {
    
    
	void swap(point& x, point& y)
	{
    
    
		x.swap(y);
	}
}

void case2()
{
    
    
	point a(1, 2, 3), b(4, 5, 6);

	cout << "std::swap" << endl;
	std::swap(a, b);

	cout << "boost::swap" << endl;
	boost::swap(a, b);
}

//

int main()
{
    
    
	case1();
	case2();
}

Guess you like

Origin blog.csdn.net/qq_36314864/article/details/132294480