O que é std::move(), e quando deve ser usado?

    O que é? O que faz?
  1. Quando Deve ser utilizado?

boas ligações são apreciadas.

Author: einpoklum, 2010-08-05

6 answers

Http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

  1. Em C++11, além de construtores de cópias, os objectos podem ter construtores de movimentos.
    (E além de operadores de atribuição de cópias, eles têm operadores de atribuição de movimento.)
  2. O Construtor de movimentos é usado em vez do construtor de cópias, se o objecto tiver o tipo "rvalue-reference" (Type &&).
  3. std::move() é um molde que produz uma referência rvalue a um objeto, para permitir que se mova dele.
É uma nova forma de c++ evitar cópias. Por exemplo, usando um construtor de movimentos, um std::vector poderia apenas copiar o seu ponteiro interno para os dados do novo objecto, deixando o objecto movido num estado incorrecto, evitando copiar todos os dados. Isto seria válido em C++. Tenta procurar no Google por semântica de movimento, rvalue, reencaminhamento perfeito.
 191
Author: Scharron, 2016-02-19 22:53:45

Você pode usar o move quando precisa de "transferir" o conteúdo de um objecto noutro lugar, sem fazer uma cópia (por exemplo, o conteúdo não é duplicado, por isso pode ser usado em alguns objectos não copiáveis, como um unique_ptr). Também é possível para um objeto tomar o conteúdo de um objeto temporário sem fazer uma cópia (e economizar muito tempo), com std::mover.

Este link ajudou-me muito. :

Http://thbecker.net/articles/rvalue_references/section_01.html

Desculpa se a minha resposta está a chegar demasiado tarde, mas também estava à procura de um bom link para a DST::move, e encontrei os links acima um pouco "austeros".

Isso colocou a ênfase na referência do valor r, em que contexto você deve usá-los, e eu acho que é mais detalhado, é por isso que eu queria compartilhar este link aqui.

 121
Author: Guillaume, 2017-11-22 06:26:53

1. "O que é?"

Embora std::move() seja tecnicamente uma função-eu diria não é realmente {[15] } Uma função . É uma espécie de conversor entre formas que o compilador considera o valor de uma expressão.

2. "O que faz?"

A primeira coisa a notar é que std::move() Não mexe em nada.

Se você já viu a série de animação Bleach - faz o equivalente a Quincy Seele Schneider 'S Reishi Softing {[[29]}.

Mas, Sério, ele converte uma expressão de ser um lvalue ou pura rvalue (tal como uma variável pode estar a utilizar por um longo tempo ainda, ou temporário, você está passando por um tempo, respectivamente) para ser um xvalue. Um xvalue diz ao compilador:

Podes pilhar-me, mover tudo o que eu estiver a segurar e usá-lo noutro lugar, já que vou ser destruído em breve. assim)".
Por outras palavras, quando se usa std::move(x), permite-se que o compilador canibalize x. Assim, se x tem, digamos, o seu próprio buffer na memória-depois de std::move() ing o compilador pode ter outro objeto próprio em vez dele.

3. "Quando deve ser usado?"

Outra maneira de fazer esta pergunta é " para que usaria/canibalizaria os recursos de um objeto?"bem, se estás a escrever código de aplicação, provavelmente não estarias a mexer muito com objectos temporários. criado pelo compilador. Então, principalmente, você faria isso em lugares como construtores, métodos de operador, funções como STL-algoritmo etc. onde os objetos são criados e destruídos automaticamente. Claro, isso é apenas uma regra de ouro.

Um uso típico é 'mover' recursos de um objecto para outro em vez de copiar. @Guillaume liga para esta página que tem um pequeno exemplo simples: trocar dois objectos com menos cópia.

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

Usar o movimento permite-te para trocar os recursos em vez de copiá-los em torno de:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Pense no que acontece quando T é, digamos, vector<int> do tamanho n. na primeira versão você lê e escreve elementos de 3*n, Na segunda versão você basicamente lê e escreve apenas os 3 pontos para os buffers dos vetores. É claro que a classe T precisa saber como fazer o movimento; você deve ter um operador de atribuição de movimento e um construtor de movimento para a classe T para que isso funcione.

 99
Author: einpoklum, 2018-10-05 12:15:49

Q: o que é std::move?

A: std::move() é uma função da Biblioteca-Padrão C++ para o vazamento para uma referência rvalue.

Simplista {[6] } é equivalente a:

static_cast<T&&>(t);

Um rvalue é um temporário que não persiste para além da expressão que o define, como um resultado de função intermediária que nunca é armazenado numa variável.

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

Uma implementação para std:: move() é dada em N2027: "A Brief Introduction to Rvalue References" as segue:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

Como pode ver, std::move devolve T&& independentemente de ser chamado com um valor (T), Tipo de Referência (T&) ou referência rvalue (T&&).

Q: O que faz?

A: como elenco, não faz nada durante a execução. É apenas relevante no tempo de compilação dizer ao compilador que você gostaria de continuar considerando a referência como um valor rvalue.
foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

O que faz Não faz:

  • Faça uma cópia do argumento
  • liga para o construtor de cópias
  • muda o objecto do argumento

Q: Quando Deve ser utilizado?

A: deverá usar std::move Se quiser chamar as funções que suportam a semântica do movimento com um argumento que não é um valor R (expressão temporária).

Isto levanta-me as seguintes perguntas:
  • O que são movimentos semânticos? A semântica do movimento em contraste com a semântica da cópia é uma técnica de programação na qual o os membros de um objeto são inicializados por 'assumir' em vez de copiar os membros de outro objeto. Tal "tomada a cargo" faz apenas sentido com ponteiros e pegas de recursos, que podem ser transferidos a baixo custo copiando o ponteiro ou punho inteiro em vez dos dados subjacentes.

  • Que tipo de classes e objetos suportam mover semântica? Cabe a você como um desenvolvedor implementar a semântica de movimento em suas próprias classes, se estes beneficiariam de transferir seus membros em vez disso de Os copiar. Uma vez que você implementa a semântica do movimento, você vai se beneficiar diretamente do trabalho de muitos programadores de bibliotecas que adicionaram suporte para lidar com as aulas com a semântica do movimento de forma eficiente.

  • Porque é que o compilador não consegue descobrir sozinho? O compilador não pode simplesmente chamar outra sobrecarga de uma função a menos que você o diga. Você deve ajudar o compilador a escolher se a versão regular ou mover da função deve ser chamada.

  • Em que situações Quero dizer ao compilador que deve tratar uma variável como um rvalue? Isso provavelmente acontecerá em funções de template ou biblioteca, onde você sabe que um resultado intermediário pode ser salvo.

 27
Author: Christopher Oezbek, 2018-05-27 21:02:16

Std::mover-se por si só não faz muito. Eu pensei que ele chamou o construtor movido para um objeto, mas ele realmente apenas executa um molde tipo (lançando uma variável lvalue para um rvalue de modo que a referida variável pode ser passada como um argumento para um construtor de movimento ou operador de atribuição).

So std:: move is just used as a precursor to using move semantics. A semântica do movimento é essencialmente uma forma eficiente de lidar com objetos temporários.

Considerar Objecto A = B + C + D + E + F;

Isto é um código bonito, mas o E + F produz um objecto temporário. Então D + temp produz outro objeto temporário e assim por diante. Em cada operador "+" normal de uma classe, cópias profundas ocorrem.

Por exemplo

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

A criação do objecto temporário nesta função é inútil-estes objectos temporários serão apagados no fim da linha à medida que saem do âmbito.

Podemos usar a semântica do movimento para "saquear" os objectos temporários e fazer algo como
 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }
Isto evita que sejam feitas cópias desnecessárias e profundas. Com referência ao exemplo, a única parte onde ocorre a cópia profunda é agora e + F. O resto usa a semântica do movimento. O construtor de movimentos ou operador de cessão também precisa ser implementado para atribuir o resultado a A.
 26
Author: user929404, 2017-02-19 15:23:32

What is it? e What does it do? foi explicado acima.

Vou dar um exemplo de when it should be used. Por exemplo, temos uma classe com muitos recursos como uma grande matriz.
class ResHeavy{ //  ResHeavy means heavy resource
    public:
        ResHeavy(int len=10):_upInt(new int[len]),_len(len){
            cout<<"default ctor"<<endl;
        }

        ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
            cout<<"copy ctor"<<endl;
        }

        ResHeavy& operator=(const ResHeavy& rhs){
            _upInt.reset(new int[rhs._len]);
            _len = rhs._len;
            cout<<"operator= ctor"<<endl;
        }

        ResHeavy(ResHeavy&& rhs){
            _upInt = std::move(rhs._upInt);
            _len = rhs._len;
            rhs._len = 0;
            cout<<"move ctor"<<endl;
        }

    // check array valid
    bool is_up_valid(){
        return _upInt != nullptr;
    }

    private:
        std::unique_ptr<int[]> _upInt; // heavy array resource
        int _len; // length of int array
};

Código de ensaio:

void test_std_move2(){
    ResHeavy rh; // only one int[]
    // operator rh

    // after some operator of rh, it becomes no-use
    // transform it to other object
    ResHeavy rh2 = std::move(rh); // rh becomes invalid

    // show rh, rh2 it valid
    if(rh.is_up_valid())
        cout<<"rh valid"<<endl;
    else
        cout<<"rh invalid"<<endl;

    if(rh2.is_up_valid())
        cout<<"rh2 valid"<<endl;
    else
        cout<<"rh2 invalid"<<endl;

    // new ResHeavy object, created by copy ctor
    ResHeavy rh3(rh2);  // two copy of int[]

    if(rh3.is_up_valid())
        cout<<"rh3 valid"<<endl;
    else
        cout<<"rh3 invalid"<<endl;
}

Saída abaixo:

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

Podemos ver que std::move com move constructor faz transformar recursos facilmente.

Onde mais está a DST: mover útil?

Std:: mover também pode ser útil ao ordenar uma série de elementos. Muito algoritmos de ordenação (como o selection sort e bubble sort) funcionam trocando pares de elementos. Anteriormente, tivemos de recorrer à semântica copiadora para fazer a troca. Agora podemos usar a semântica do movimento, que é mais eficiente.

Também pode ser útil se quisermos mover o conteúdo gerido por um ponteiro inteligente para outro.

Citado:

Https://www.learncpp.com/cpp-tutorial/15-4-stdmove/

 0
Author: Jayhello, 2018-09-22 11:41:53