Posso chamar um construtor de cópia explicitamente?
-
19-09-2019 - |
Pergunta
Estou um pouco confuso quanto à mecânica do construtor de cópia. Corrija-me se eu estiver errado:
Se um método leva uma referência a um objeto como um parâmetro, e a classe define um construtor de cópia, então a classe usa o construtor para criar uma cópia de si mesmo e que é passada para a função em vez de uma referência ao original objeto?
Além disso, pode-se chamar
Object * obj = new Object(&anotherObject);
para criar uma cópia de anotherObject?
Solução
Não, se uma função de dar uma referência:
void f1( Object & o ); // call by reference
, em seguida, nenhuma cópia é feita. Se uma função tem um valor:
void f2( Object o ); // call by value
, em seguida, uma cópia é criada pelo compilador usando o construtor de cópia.
E sim, quando você diz:
Object * obj = new Object(anotherObject); // not &anotherObject
o construtor de cópia é usado explicitamente (assumindo anotherObject é do tipo Object.) Não há nada mágico sobre o uso de new
aqui, no entanto - neste caso:
Object obj2(anotherObject);
o construtor de cópia também é usado.
Outras dicas
Se um método leva uma referência a um objeto como um parâmetro , construtor de cópia não será chamado. Se fosse esse o caso, então uma chamada para o próprio construtor de cópia teria resultado em um loop infinito (uma vez que leva uma referência como um argumento).
Essa linha não é uma forma válida para chamar um construtor de cópia. Ele espera uma referência como um argumento, não um ponteiro.
O fato de que você está fazendo uma chamada de método não é importante aqui. inicialização parâmetro de referência durante uma chamada de função não é diferente de uma inicialização de referência autônomo e é regido pelas mesmas regras.
As regras de inicialização de referência são um pouco complicado, mas a linha de fundo é que se o inicializador é um lvalue (o argumento na chamada de método no seu caso) e o tipo de referência é o mesmo que o tipo de inicializador (isto é, tipo do parâmetro é o mesmo que o tipo de argumento), em seguida, a referência será ligado directamente. Ou seja, não é criada cópia.
Object a; // class type
Object &r = a; // no copying
const Object &cr = a; // no copying
Se estes requisitos não forem cumpridos (como se o inicializador é um rvalue, por exemplo), então tudo depende. Em alguns casos, a cópia pode e terá lugar. Por exemplo
const Object &tr = Object();
pode ser interpretado pelo compilador como
const Object &tr = Object(Object(Object(Object())));
com número finito dependente da implementação de copyings. Claro que, por razões de eficiência compiladores normalmente não são tentando criar cópias desnecessárias, mesmo quando eles estão autorizados a copiar.
Um exemplo clássico que muitas vezes agita debate sobre a validade do comportamento copiando do compilador é a inicialização de referência em expressões como a seguinte
Object a;
const Object &r = <some condition> ? a : Object();
Uma pessoa familiarizada com semântica de referência C ++ iria entender que as expressões como o acima são susceptíveis a lógica por trás a permissão padrão para realizar a cópia supérfluo durante a inicialização de referência.
Não em ambos os casos. No primeiro caso, referência a esse objeto em si é passado e cópia não é criado. No segundo caso, você está passando um ponteiro para o construtor de object
, portanto, nenhuma cópia é criada. Então objeto deve ter um construtor (não é um construtor de cópia), que é algo como object(anotherClass*)
Copiar só é chamado quando passar por valor , não por referência . Por referência não é necessária nenhuma cópia (isto é parte do que referências são para!) Assim, não construtor de cópia chamado.
sim usando posicionamento novo assim:
Object dstObject;
new(&dstObject) Object(&anotherObject);