Não confunda parâmetro por referência em construtor de cópia

Autor alex Data 2017-11-02
C++
Não confunda parâmetro por referência em construtor de cópia

Sempre que eu encontrava a expressão “Copy constructor” ou “Construtor de cópia” e o parâmetro tinha um &, eu ficava tentando lembrar do porquê o nome era “por cópia…” se o parâmetro estava sendo passado por referência. Calma, se você não trabalha com c++ todos os dias, isso não é algo tão absurdo de se esquecer.

Olhe o código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyContainer
{
int sz; // numero de elementos
int* elems; // Um ponteiro para os elementos
public:
MyContainer(int s)
: sz(s)
, elems(new int[s])
{}
~MyContainer()
{
delete[] elems;
}
};
int main()
{
MyContainer c1(5);
MyContainer c2(c1);
return 0;
}

Infelizmente esse código compila, porque como MyContainer não declara nenhum construtor por cópia e nem um operador de atribuição por cópia, então os compiladores gerarão essas funções (se forem necessárias). Para ter certeza que o compilador gerou um construtor de cópia (além do fato de compilar), vamos ver no clang-check, rodando o comando:

1
clang-check -ast-dump Source.cpp

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
`-FunctionDecl 0x6e4e170 <line:17:1, line:22:1> line:17:5 main 'int (void)'
`-CompoundStmt 0x6e4e610 <line:18:1, line:22:1>
|-DeclStmt 0x6e4e3e0 <line:19:2, col:19>
| `-VarDecl 0x6e4e228 <col:2, col:18> col:14 used c1 'class MyContainer' callinit
| `-CXXConstructExpr 0x6e4e3b8 <col:14, col:18> 'class MyContainer' 'void (int) __attribute__((thiscall))'
| `-IntegerLiteral 0x6e4e260 <col:17> 'int' 5
|-DeclStmt 0x6e4e5d0 <line:20:2, col:20>
| `-VarDecl 0x6e4e410 <col:2, col:19> col:14 c2 'class MyContainer' callinit
| `-CXXConstructExpr 0x6e4e5a8 <col:14, col:19> 'class MyContainer' 'void (const class MyContainer &) __attribute__((thiscall)) noexcept'
| `-ImplicitCastExpr 0x6e4e468 <col:17> 'const class MyContainer' lvalue <NoOp>
| `-DeclRefExpr 0x6e4e3f0 <col:17> 'class MyContainer' lvalue Var 0x6e4e228 'c1' 'class MyContainer'
`-ReturnStmt 0x6e4e600 <line:21:2, col:9>
`-IntegerLiteral 0x6e4e5e0 <col:9> 'int' 0

Veja que a linha 9 do Output que se refere a linha 20 da source, está chamando o construtor de cópia gerado pelo Compilador.

Isso foi apenas para mostrar porque o código compilou, mesmo sendo um código que vai explodir no destrutor porque o membro ponteiro “elems” é apontado para o mesmo endereço em c1 e c2.

Voltando ao título

Então porque tem uma referência no construtor de cópia? A resposta é que ele precisa receber como argumento uma referência ao objeto que deve copiar. É referência e não cópia, porque não queremos copiar o argumento do construtor, que define o que copiar. Falando de forma mais simples ainda, se chama construtor de cópia, porque a função dele é copiar todos os elementos de um objeto de um mesmo tipo para outro.

Um pouco besta, mas de vez em quando eu me pegava nessa dúvida haha.

Quando eu melhorar minhas skills em assembly, eu faço um update no post utilizando o VC++, no momento não deu muito certo ;)