Guía de desarrollo de Boost-4.5swap

intercambio

boost::swap es una mejora y generalización de std::swap en la biblioteca estándar. Proporciona un método conveniente para intercambiar los valores de dos variables (que pueden ser tipos de datos integrados como int, o instancias de clase o contenedores).

Para utilizar boost::swap, es necesario incluir el archivo de encabezado <boost/swap.hpp>, es decir

#include<boost/swap.hpp>

principio

std::swap() en el estándar C++98

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

Como se puede ver en el código, std::swap() requiere que el objeto intercambiado sea copiable y asignable. Proporciona el método más versátil y menos eficiente, que requiere una construcción de copia y dos asignaciones. La operación puede resultar bastante caro si los objetos que se intercambian son grandes.

El estándar C++ 11 utiliza semántica de transferencia para optimizar std::swap() y evitar el costo de la copia.

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
}

Pero no todas las clases implementan sus propias construcciones de transferencia y funciones de asignación, y el soporte del compilador también es un tema que debe considerarse, por lo que para las clases que escribimos nosotros mismos, es mejor implementar swap() optimizado para mejorar la eficiencia.

Hay dos soluciones: la primera solución es usar directamente la sobrecarga de funciones y escribir una función swap_ con el mismo nombre. Este swap() luego llama a la función eficiente de intercambio de miembros dentro de la clase, de modo que el compilador no use std durante la compilación. ::intercambio(). La segunda opción es utilizar ADrR para encontrar la especialización de plantilla de std::swap. Estas dos soluciones son cómo funciona boost::swap.

boost::swap busca una especialización de std::swap() de tipo T o busca un swap() especializado en plantilla a través de ADL. Si es así, lo llama. Si ambas búsquedas fallan, se degrada a std::swap (). Además, boost::swap también agrega una característica muy práctica: soporte para el intercambio de matrices integrado de C++ (se ha incluido en el estándar C++ 11).

La declaración de la función boost::swap() es:

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

Dado que boost::swap() tiene el mismo nombre que std::swap(), no podemos usar la declaración de uso para abrir el espacio de nombres de boost. Siempre debemos llamarlo de una manera calificada para el espacio de nombres de boost.

Intercambio de matrices

boost::swap puede intercambiar directamente el contenido de dos matrices, pero las dos matrices que participan en el intercambio deben tener la misma longitud. El siguiente código utiliza el algoritmo de biblioteca estándar fill_n para asignar las dos matrices a 5 y 20 respectivamente, y luego llama a boost::swap() para intercambiar:

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

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

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

La implementación de boost::swap para intercambiar el contenido de una matriz es muy simple: utiliza un bucle for para llamar a una versión de un solo elemento de boost::swap para cada elemento de la matriz para completar el intercambio de todo el contenido de la matriz. Después de ejecutar el código anterior, el valor del elemento en a1 será 20 y el valor del elemento en a2 será 5.

Si intenta utilizar boost::swap para intercambiar dos matrices de diferentes longitudes, no se compilará:

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

std especializado::intercambio

A continuación, utilizamos un punto simple en un espacio tridimensional como ejemplo para demostrar el método de especialización de plantilla usando boost::swap. Implementa una función de intercambio interna eficiente:

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;
	}
};

Especializarse en std::swap() requiere agregar una función personalizada al espacio de nombres estándar:

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
}

Dado que tenemos std::swap especializado en el espacio de nombres, boost::swap tiene el mismo efecto que std::swap, ambos usan la función de intercambio especializada.

Especializar el intercambio localizable de ADL

Sigo usando la clase de puntos en este momento, pero esta vez no cambiamos el espacio de nombres estándar, sino que implementamos la función de intercambio en el dominio global:

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
}

El resultado de ejecución de este código es significativamente diferente de la especialización anterior de std::swap. std::swap usa operaciones de intercambio estándar, mientras que boost::swap encuentra la función de intercambio especializada del espacio de nombres global a través de reglas ADL e implementa para un intercambio eficiente. .

Si a los lectores les preocupa que escribir un intercambio de funciones gratuito en el espacio de nombres global cause "contaminación" en el nombre, pueden agregar el intercambio especializado al espacio de nombres boost u otros espacios de nombres que ADL pueda encontrar.

ejemplo de código

#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();
}

Supongo que te gusta

Origin blog.csdn.net/qq_36314864/article/details/132294480
Recomendado
Clasificación