Pular para conteúdo

Semântica de Cópia e Movimentação

Copiar cria valor independente segundo o contrato do tipo. Mover permite que um novo objeto reutilize recursos de outro que não é mais necessário no estado atual.

Funções-membro especiais

Uma classe pode ter destrutor, construtor/atribuição de cópia e de movimentação. Declarar algumas afeta a geração implícita das outras. Prefira a Regra do Zero.

class document {
public:
    document(std::string title, std::vector<std::string> lines)
        : title_{std::move(title)}, lines_{std::move(lines)} {}

private:
    std::string title_;
    std::vector<std::string> lines_;
}; // compiler-generated copy and move operations are appropriate

std::move não move

std::move(expression) converte o argumento em xvalue, permitindo selecionar overloads de movimentação. O construtor ou função selecionado realiza a transferência.

std::string source{"data"};
std::string destination = std::move(source);

Após mover, objetos da biblioteca ficam válidos, mas em estado não especificado, salvo contrato mais forte. Podem ser destruídos ou receber atribuição; não presuma vazio.

Eliminação de cópia

std::vector<int> sequence() {
    std::vector<int> result{1, 2, 3};
    return result;
}

Casos garantidos e NRVO evitam muitas cópias. return std::move(result); pode impedir NRVO e normalmente não otimiza.

Tipo proprietário de recurso

Se a classe possui handle não RAII, a Regra dos Cinco pede revisão. Uma política comum é permitir movimento e proibir cópia:

class file_handle {
public:
    file_handle(file_handle const&) = delete;
    file_handle& operator=(file_handle const&) = delete;
    file_handle(file_handle&& other) noexcept;
    file_handle& operator=(file_handle&& other) noexcept;
    ~file_handle();
};

Movimentos devem deixar ambos destrutíveis e atribuíveis. noexcept, quando verdadeiro, permite que contêineres preservem garantias fortes na realocação.

Forwarding

Perfect forwarding preserva a categoria de valor por referências de forwarding e std::forward. Use apenas em wrappers genéricos; uso indiscriminado oculta posse e overload.

Exercícios

  1. Explique por que std::move em objeto const costuma copiar.
  2. Projete contratos de cópia/movimento para socket exclusivo.
  3. Explique por que objeto movido não significa vazio.