Eficaz C ++ cláusula 44: Modelos y programación genérica de (no relacionada con las plantillas de código de parámetro tirados)

Un código correspondiente a Estrategias repetidas

para la función de

  • Supongamos que escribimos ciertas funciones (más de uno), hay algunas de estas funciones cuando el código es el mismo, por lo que creemos que este es el código para el programa se repite
  • Así que en este momento puedo ser una parte común de estas funciones se extraen, y luego se coloca en otra función, por lo que la nueva función llama a esta función tenía esos. Esto logra el efecto de reducir el código

Para los propósitos de la clase

  • Supongamos que escribimos un conjunto de clases, y estas clases en algunas partes son los mismos, por lo que creemos que este es el código para el programa se repite
  • Así que en este momento podemos ser parte de estas clases se extraen juntos, crear una nueva clase , y luego dejar que las clases habían heredado de esta nueva clase. Esto logra el efecto de reducir el código

Para la plantilla (plantilla función de plantilla / clase) es

  • Sabemos que el código sólo se creará una instancia cuando se usa la plantilla, y para cada instancia, genera un código que corresponde al código , por lo que para cada uno instanciado entre los mismos puede generar la duplicación de código fenómeno
  • Para una función / clase normal, la repetición de código se ve fácilmente (por códigos). Pero para la plantilla, no es fácil de encontrar, porque la única plantilla se crea una instancia, ya sabes lo plantilla de contenido generado

En segundo lugar, el caso de demostración

  • Supongamos ahora que, teniendo tal clase una plantilla, que se utiliza para representar de tamaño fijo matriz cuadrada , esta matriz también es un método de soporte de la operación de matriz inversa. Código es el siguiente:
//矩阵的元素类型为T,矩阵的大小为n*n类型(模板第二个类型为非类型参数)
template<typename T, std::size_t n>
class SquareMatrix {
public:
    void invert(); //求逆矩阵
};
  • Supongamos que tenemos la siguiente llamada, por lo que llamar a la función invertido (), puede dar lugar a hinchazón de código. Los siguientes razones:
    • Por debajo de 5 * 10 * 5 de matriz y la matriz 10 son llamados invertido (), la función se utiliza para la inversión de la matriz
    • Sin embargo, según invertido () vista de código de aplicación, que además de la matriz como los tamaños, invertido () matriz de procesamiento para el otro código es el mismo, por lo tanto la generación de la duplicación de código por encima de dos plantillas generadas donde
SquareMatrix<double,5> sm1;
sm1.invert();

SquareMatrix<double,10> sm2;
sm2.invert();

primera Revisión

  • Debido a que el código invertido () producirá por duplicado, por lo que ahora establecemos la siguiente jerarquía de herencia . Código es el siguiente:
    • Hemos modificado la plantilla de clase Matriz cuadrada llamado SquareMatrixBase, para aceptar sólo tipo de matriz, agregar un parámetro para invertir (), que se utiliza para indicar el tamaño de la matriz de mango
    • Añadir una plantilla Matrizcuadrada hereda su clase, proporcionando ellos con un tamaño size_t parámetro de plantilla de la matriz utiliza para representar el proceso de
//不论SquareMatrix产生多少粉,SquareMatrixBase在代码中只产生一份
template<typename T>
class SquareMatrixBase {
protected:
    void invert(std::size_t matrixSize);
};

template<typename T,std::size_t n>
class SquareMatrix :private SquareMatrixBase<T>
{
private:
    using SquareMatrixBase<T>::invert; //避免派生类隐藏基类的invert函数
public:
    void invert() {
        this->invert(n); //为什么使用this,参阅条款43
    }
};
  • Aquí ahorro en comparación con el primer código de razón:
    • Cuando Matrizcuadrada instancia, que no produce demasiado código, debido a su clase base llamada directamente invertido función
    • Puesto que la clase base, y no va a invertir debido a las diferentes matrices de diferentes tamaños y ejemplos de la clase de plantilla, porque genera una plantilla de código de clase, dependiendo del tamaño de la matriz, en el que la función () llamada puede ser invertido
  • Algunas notas de sintaxis:
    • Dado que las funciones SquareMatrixBase para lograr una clase derivada, por lo que el SquareMatrixBase invertido en la función () se declara como protegido, no se les permite operar fuera de la directa SquareMatrixBase
    • Matriz cuadrada utilizar la herencia privado a SquareMatrixBase, debido a su uso de la tecnología se introduce en frente del " Implementado Los-terms-de (según lograr algo) " la tecnología (se puede ver la cláusula 38, 39)
    • Además, en el invertido Matrizcuadrada () en la llamada invertido clase base () usando este puntero (que se puede ver el contenido de la cláusula 43)

La segunda enmienda

  • Ahora hay un problema:
    • SquareMatrixBase () para completar el procesamiento de la matriz de datos, pero ¿cómo se sabe SquareMatrixBase proceso de donde?
    • Así, el Matrizcuadrada () debe utilizar un método, la operación de transferencia de datos a SquareMatrixBase ()
  • solución:
    • ① (indeseable método): es SquareMatrixBase () :: invertido () proporciona una matriz de parámetros puntero utilizado para representar los datos a procesar. Por lo tanto hacer lo mismo proveedor de electricidad porción indeseable porque SquareMatrixBase () la operación se requiere toda esta clase de datos, si hay muchos miembros SquareMatrixBase método (), entonces usted tendrá que proporcionar un puntero para cada miembro del método, de modo que formas no deseadas
    • ② (el método de esta operaciones de revisión): en SquareMatrixBase () almacena un puntero a la memoria de datos para almacenar la matriz para ser operado (esta memoria de la clase derivada). Código es el siguiente:
template<typename T>
class SquareMatrixBase {
    //其余同上
protected:
    SquareMatrixBase(std::size_t n, T* pMem)
        :size(n), pData(pMem) {}

    void setDataPtr(T* ptr) { pData = ptr; } //更改pData的数据
private:
    std::size_t size; //矩阵的大小
    T* pData;         //指向矩阵的内容
};
  • El código de clase derivada como sigue: pasará un puntero a la matriz de memoria real propia base de datos a código de manejo de clase es el siguiente:
template<typename T, std::size_t n>
class SquareMatrix :private SquareMatrixBase<T>
{
    //其他同上
public:
    SquareMatrix():
        SquareMatrixBase<T>(n, data) {} //将存储矩阵数据的指针传递给基类
private:
    T data[n*n]; //存储矩阵的实际数据
};

tercera revisión

  • Seguido de "La segunda enmienda," Vamos a por encima de la matriz de datos almacenados en la clase Matrizcuadrada puede hacer que el objeto en sí es muy grande Matrizcuadrada
  • Otro enfoque es: los datos almacenados en la matriz montón . Código es el siguiente:
template<typename T, std::size_t n>
class SquareMatrix :private SquareMatrixBase<T>
{
public:
    SquareMatrix():
        SquareMatrixBase<T>(n, 0), pData(new T[n*n])
    {
        //将它的一个副本交给base class
        this->setDataPtr(pData.get());
    }
private:
    boost::scoped_array<T> pData;
};
  • Después de tres revisiones, el código ha sido optimizado con respecto a la comparación de los detalles específicos que:
    • función miembro Matrizcuadrada simplemente invocar a SquareMatrixBase inline versión
    • clase SquareMatrixBase de "mantener el mismo tipo de elemento, pero diferente matriz de tamaño" cuota de clase de objeto el Matrizcuadrada
    • Y hemos añadido una función setDataPtr () SquareMatrixBase, así que cuando nos movemos diferentes objetos Matrizcuadrada (por ejemplo Matrizcuadrada <doble, 5> y Matrizcuadrada <doble, 10>), la operación no preocupación acerca de un objeto a otro objeto de datos, debido a que usamos setDataPtr () se proporciona en el puntero de datos matriz SquareMatrixBase
  • Varias instrucciones sobre la eficiencia del código:
    • ①SquareMatrix la función invertido (), puede invertir a la versión compartida (SquareMatrixBase a) de la función () para generar un mejor código. Matrizcuadrada ejemplo, el tamaño de la matriz es una constantes de compilación, es posible transmitir una amplia por la optimización constante, incluyendo doblarlos en la instrucción se genera como un operando directa. Esto no se puede hacer de SquareMatrixBase
    • ② diferente matriz de tamaño con sólo una única versión de la solera () (SquareMatrixBase in), puede reducir el tamaño del archivo ejecutable, por lo tanto también la reducción del tamaño del programa del conjunto de trabajo, y para fortalecer la directiva le dice a la centralización referencias a la zona de caché. Estos programas pueden hacer una ejecución más rápida
      • El llamado conjunto de trabajo se refiere a un procedimiento para la ejecución de "entorno de memoria virtual", el grupo que utilizan páginas de memoria
    • Otro tema ③ evaluación del desempeño tiene que ver con el tamaño del objeto: almacenamos en la Matriz cuadrada en un puntero a la matriz de datos, de modo de bloqueo Matrizcuadrada objetos creados aumenta el tamaño.
      • Otro enfoque: la eliminación de Matrizcuadrada el puntero, de modo que un protegido puntero SquareMatrixBase de almacenamiento a la matriz de datos. Sin embargo, esto puede conducir a la pérdida de encapsulación, otro puede dar lugar a confusión en el manejo y la complejidad de los recursos (véase la cláusula 22)
      • Por lo tanto, Matrizcuadrada almacenar punteros, a pesar de un aumento de un poco de espacio, pero los pros y los contras, vale la pena

En tercer lugar, adicional

  • Esta disposición es discutir expansión provocada por parámetros no tipo de plantilla (parámetros de plantilla no tipo), de hecho, parámetros de tipo (parámetros de tipo) también pueden causar hinchazón

por ejemplo

  • Muchas plataformas int y largo tener la misma representación binaria
  • Por lo tanto vector <int> y el vector <long> función miembro puede tener exactamente el mismo - causa la duplicación de código / expansión
  • Algunos enlazador (enlazadores) se fusionaron para lograr el mismo código de función, pero algunos no lo hará
  • por lo tanto Algunas plantillas están configurados como int y largo dos versiones, entonces la duplicación de código / expansión resultante

por ejemplo

  • En la mayoría de las plataformas, todos los tipos de puntero tienen la misma representación binaria
  • Así que si un puntero tiene plantillas, por ejemplo, List <int *>, lista <const int *>, la lista <Matriz cuadrada <larga, 3> *>, etc., tienden a responder a todas y cada función miembro utiliza una implementación subyacente único
  • Típicamente veces con medio, si a alcanzar ciertas funciones miembro y su funcionamiento fuerte tipo de puntero (es decir, T *), debe llamar a otro de modo que operan sin el tipo (es decir, void *) puntero de función, que se realiza por trabajo real
  • Alguna versión implementación en C ++ biblioteca estándar de hecho hacer estas cosas para el vector, deque, lista y otras plantillas. Si usted se preocupa por sus plantillas pueden surgir código hinchazón, también querrá sus plantillas también utilizan estas técnicas

IV Resumen

  • Plantillas generar una pluralidad de clases y una pluralidad de funciones, por lo que cualquier plantilla no hacen que la plantilla de código con una expansión de producción dependencias de parámetros
  • Código debido a los parámetros de plantilla no de tipo causados ​​por la inflamación a menudo puede ser eliminada, la práctica consiste en sustituir los parámetros de la función parámetro de plantilla o variables miembro de clase
  • Parámetro Código Tipo causado debido a la expansión, tiende a reducirse, con el enfoque es dejar que la representación binaria del mismo tipo que tiene ahora consigue el código compartido
Liberadas 1525 artículos originales · ganado elogios 1084 · Vistas de 450.000 +

Supongo que te gusta

Origin blog.csdn.net/qq_41453285/article/details/104856465
Recomendado
Clasificación