Pergunta

Como alguns dos meu código necessário conversão implícita entre matrizes de tipos diferentes (por exemplo Matrix<int> para Matrix<double>), que definida uma cópia construtor Matrix<T>::Matrix(Matrix<U> const&) modelada em vez do Matrix<T>::Matrix(Matrix<T> const&) padrão:

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

Com um estereotipado adequado adicionado à cópia-construtor, este método perfeitamente convertidos entre as matrizes de diferentes tipos. Surpreendentemente, ele falha com um erro de malloc na mesma situação em que uma cópia construtor simples funcionaria: onde U == T. o suficiente certeza, sobrecarregando o copy-construtor com os resolve assinatura Matrix<T>::Matrix(Matrix<T> const&) padrão o problema.

Esta é uma má solução, uma vez que resulta na duplicação atacado do código copy-construtor (Literalmente uma cópia e colar inalterado). Mais importante, eu não entendo por que há um erro de double-free malloc sem o código duplicado. Além disso, por que é extremamente detalhado sintaxe template <typename T> template <typename U> necessária aqui, em oposição ao padrão, e muito mais sucinta, template <typename T, typename U>?

-fonte completo do método templated, compilado usando G ++ v4.0.1 no 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));
        }
    }
}
Foi útil?

Solução

Ele falha porque um modelo não suprime a declaração implícita de um construtor de cópia. Ele irá servir como uma simples conversão de construtor, que pode ser usado para copiar um objecto quando selecciona a resolução de sobrecarga-lo.

Agora, você provavelmente copiou o seu em algum lugar matriz, que usaria o construtor de cópia definido implicitamente que faz uma cópia simples. Em seguida, a matriz copiado e a cópia seria tanto em seu destruidor excluir o mesmo ponteiro.

Além disso, por que é extremamente detalhado sintaxe template <typename T> template <typename U> necessário

Porque existem dois modelos envolvidos: The Matrix, que é um modelo de classe, eo modelo de construtor de conversão. Cada modelo merece sua própria cláusula modelo com seus próprios parâmetros.

Você deve se livrar do <T> em sua primeira linha, pela maneira. coisa tal não aparece quando definir um modelo.

Esta é uma má solução, uma vez que resulta na duplicação atacado do código cópia construtor

Você pode definir um modelo de função de membro, que vai fazer o trabalho, e delegar tanto o construtor conversão e o construtor de cópia. Dessa forma, o código não é duplicada.


Richard fez um bom ponto nos comentários que me fez alterar a minha resposta. Se a função de candidato gerado a partir do modelo é um jogo melhor do que o construtor de cópia declarou implicitamente, em seguida, os modelo "ganha", e ele será chamado. Aqui estão dois exemplos comuns:

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

Um construtor de cópia pode ter um parâmetro de referência não-const também, se qualquer de seus membros tem

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

Outras dicas

Eu não sou inteiramente claro da sua pergunta, mas eu suspeito que está acontecendo é que o construtor de cópia padrão (que faz um memberwise cópia somente) está sendo usado em alguns lugares em seu código. Lembre-se, não só o código que você usa realmente escrever o construtor de cópia -. Os usos do compilador também

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top