Pregunta

Como algunos de mi código requerido para la conversión implícita entre las matrices de diferentes tipos (por ejemplo, Matrix<int> a Matrix<double>), He definido una plantilla constructor de copia Matrix<T>::Matrix(Matrix<U> const&) en lugar de la estándar Matrix<T>::Matrix(Matrix<T> const&):

template <typename T> class Matrix {
public:
    // ...
    template <typename U> Matrix(Matrix<U> const&);
    // ...
private
    unsigned int m_rows, m_cols;
    T *m_data;
    // ...
};

Con una adecuada encasillado añadido para el constructor de copia, este método sin problemas convertir entre matrices de diferentes tipos.Sorprendentemente, se produce un error con un malloc error en la misma situación, donde un simple constructor de copia funcionaría:donde U == T.Efectivamente, la sobrecarga del constructor de copia por defecto con el Matrix<T>::Matrix(Matrix<T> const&) la firma se soluciona el problema.

Esta es una mala solución, ya que los resultados en la venta al por mayor de la duplicación del constructor de copia el código (Literalmente cambio de copiar y pegar).Lo que es más importante, no entiendo por qué hay un doble-gratis malloc error sin el código duplicado.Además, ¿por qué el muy detallado template <typename T> template <typename U> sintaxis necesaria aquí en oposición a la norma, y mucho más sucinta, template <typename T, typename U>?

Fuente completo de la plantilla de método, construido a partir de G++ v4.0.1 en Mac OS 10.5.

template <typename T> template <typename U> Matrix<T>::Matrix(Matrix<U> const& obj) {
    m_rows = obj.GetNumRows();
    m_cols = obj.GetNumCols();
    m_data = new T[m_rows * m_cols];

    for (unsigned int r = 0; r < m_rows; ++r) {
        for (unsigned int c = 0; c < m_cols; ++c) {
            m_data[m_rows * r + c] = static_cast<T>(obj(r, c));
        }
    }
}
¿Fue útil?

Solución

Se produce un error debido a una plantilla no suprime la declaración implícita de un constructor de copia. Servirá como un simple constructor de conversión, que se puede utilizar para copiar un objeto cuando la resolución de sobrecarga selecciona.

Ahora, es probable que copian su matriz en alguna parte, que pueden utilizar el constructor de copia definido implícitamente que no hace una copia plana. Entonces, la matriz de copiado y la copia serían tanto en su destructor borrar el mismo puntero.

  

Por otra parte, ¿por qué es necesaria la sintaxis template <typename T> template <typename U> extremadamente verboso

Debido a que hay dos plantillas implicadas: la matriz, que es una plantilla de clase, y la plantilla de constructor de conversión. Cada plantilla se merece su propia cláusula plantilla con sus propios parámetros.

Se debe deshacerse de la <T> en su primera línea, por cierto. Tal cosa no aparece cuando se define una plantilla.

  

Esta es una mala solución, ya que da lugar a la duplicación del código por mayor constructor de copia

Puede definir una plantilla de función miembro, que va a hacer el trabajo, y delegar tanto del constructor de la conversión y el constructor de copia. De esta manera, el código no se duplica.


Richard hizo un buen punto en los comentarios que me hicieron enmendar mi respuesta. Si la función candidata generado a partir de la plantilla es un partido mejor que el constructor de copia declarado implícitamente, la plantilla "gana", y que serán llamados. He aquí dos ejemplos comunes:

struct A {
  template<typename T>
  A(T&) { std::cout << "A(T&)"; }
  A() { }
};

int main() {
  A a;
  A b(a); // template wins:
          //   A<A>(A&)  -- specialization
          //   A(A const&); -- implicit copy constructor
          // (prefer less qualification)

  A const a1;
  A b1(a1); // implicit copy constructor wins: 
            //   A(A const&) -- specialization
            //   A(A const&) -- implicit copy constructor
            // (prefer non-template)
}

A constructor de copia puede tener un parámetro de referencia no const también, si cualquiera de sus miembros tiene

struct B { B(B&) { } B() { } };
struct A {
  template<typename T>
  A(T&) { std::cout << "A(T&)"; }
  A() { }
  B b;
};

int main() {
  A a;
  A b(a); // implicit copy constructor wins:
          //   A<A>(A&)  -- specialization
          //   A(A&); -- implicit copy constructor
          // (prefer non-template)

  A const a1;
  A b1(a1); // template wins: 
            //   A(A const&) -- specialization
            // (implicit copy constructor not viable)
}

Otros consejos

No estoy del todo claro por su pregunta, pero sospecho que lo que está sucediendo es que el constructor de copia por defecto (que hace una copia única miembro por miembro) se está utilizando en algunos lugares en su código. Recuerde, no sólo el código que escribe realmente utiliza el constructor de copia -. El compilador utiliza demasiado

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top