Há algum ponto para definir objetos movidos apenas em C++11?

Eu tinha uma pergunta sobre o uso do unique-ptrs antes. Eu entendo esta resposta recomendando usar objetos movidos apenas. Defini uma classe do seguinte modo:

class B {
    const string objName;
public:

    B ( B && ) = default;
    B &  operator= ( B && ) = default;
    B ( const B & ) = delete;
    B & operator= ( const B & ) = delete;

    B(const string & name) :
            objName(name) {

    }

    virtual ~B();

    const string name() const { return objName;};
}

e eu chamei B por estas linhas:

class A {
A(){}
void take(B b);
}

A a; 
B b("test");
cout<<b.name();
a.take(std::move(b));
cout<<b.name();

As minhas perguntas:

  1. Mesmo que eu tenha faltado ao construtor de movimentos, Eu não posso escrever A. take(b) e estou recebendo erro de compilação. Compreendo que a copy constructor seja apagada, mas parece que a escolha lógica é usar o construtor de movimento quando está em falta sem necessidade de escrever std:: mover assim A. take (B)
  2. No resultado, o" teste " é impresso duas vezes. Por que o objeto b não foi removido depois de chamar o movimento? Se o objecto b ainda existir e uma cópia dele tiver sido enviada para o A. take(mover(B)), então significa que não temos qualquer uso do movimento para objectos rvalue.
  3. é uma boa prática usar objetos apenas em movimento como acima (remover o construtor de cópia e Operador de atribuição e construtor de movimento em falta e mover missão)?
Author: Community, 2015-10-24

2 answers

Sim, há um ponto. Objetos que gerem recursos (talvez físicos) que não podem/não devem ser compartilhados entre objetos é o primeiro exemplo que vem à mente. Escreveu-o incorrectamente. Aqui está o que eu acho que você quer baseado nesta pergunta e na sua anterior.
class B {
    std::string objName;
public:
    B ( B && ) = default;
    B &  operator= ( B && ) = default;
    B ( const B & ) = delete;
    B & operator= ( const B & ) = delete;
    B(const std::string & name) :
            objName(name) {}
    virtual ~B() {}
    std::string name() const { return objName;}
};

class A {
public:
   std::vector<B> v;
   void take(B && b)
   {
      v.push_back(std::move(b));
   }
};

int main()
{
   A a;
   B b("test");

   std::cout << "Before: " << b.name() << std::endl;
   a.take(std::move(b));
   std::cout << "After: " << b.name() << std::endl;

   std::cout << "A has elements: " << std::endl;
   for(B &b : a.v)
      std::cout << "  " << b.name() << std::endl;
}
Estás a aceder a um valor que foi transferido, o que não faz sentido nenhum! esta resposta {[8] } já faz um bom trabalho de explicar, mas abaixo eu também incluí texto de a STL reference for std:: move.

Http://en.cppreference.com/w/cpp/utility/move

Salvo indicação em contrário, todos os objectos normais de biblioteca que tenham foi movido de são colocados em um estado válido, mas não especificado. Isto é ... , apenas as funções sem pré-condições, como a atribuição operador, pode ser usado com segurança no objeto depois que ele foi movido.

Encontrei dois usos legítimos na minha experiência. Em ambos os casos a mudança-apenas os objetos controlavam um recurso físico que se compartilhado por dois objetos quebraria tudo.
 5
Author: tweej, 2018-08-24 08:59:08
Por volta das 3: claro que há. Eu posso pensar em muitos exemplos de objetos que podem ser movidos e não ser copiados, ou shoudln não, de qualquer forma.

Um exemplo é uma classe de 'Socket':
1) você quer dar um construtor padrão para o Socket "vazio" que ainda não recebeu nenhum IP ou porto.
2) você quer dar um construtor que recebe um IP e porta. após a construção, o 'Socket' irá tentar ligar-se e poderá abrir uma excepção se a ligação falhar
3) a coisa óbvia é o destruidor - desligará o objecto e libertará todos os recursos do sistema subjacente que este objecto possa deter.

E quanto ao construtor de movimentos contra construtor de cópias?
digamos que tenho uma função que cria uma tomada e devolve-a. Se eu ligar para o construtor de cópias isso significa que:
o novo socket copiado (return value) tentará conectar-se ao mesmo IP e porta a que o socket de origem foi conectado. isso pode não ser possível.
o 'socket' de origem será desligado e destruído
É possível que tentar copiar o socket só crie uma enorme confusão. pelo contrário, um construtor de movimentos resolve esta massa com cuidado:
o valor de retorno recebe todos os recursos operacionais subjacentes sem desconectá-los ou destruí-los.
o soquete de origem fica vazio e o destruidor não tem nada para desligar ou destruir.

Parece que os 'sockets' provavelmente só seriam movidos, não copiados.

Isto pode aplicar-se a Classe "processo" - se eu tentar retornar um processo copiando, eu poderia tentar abrir o mesmo processo novamente, apenas para desligar o original. uma confusão! ao mover o processo, não o faço. Eu simplesmente movo o processo de uma função para outra.

 2
Author: David Haim, 2015-10-24 14:29:41