Как здесь работает семантика перемещения? - PullRequest
2 голосов
/ 10 января 2020

У меня есть следующий пример, и я не уверен, что полностью понимаю ход semanti c logi c:

#include <iostream>
#include <string>
#include <memory>

class Player
{
public:
    Player(std::string name)
        : m_name(std::move(name)) {}

private:
    std::string m_name;
};

int main()
{
    std::string s = "Zidane";
    std::cout << s << std::endl;

    Player player1(s); // not moved
    std::cout << s << std::endl; // s = "Zidane"

    Player player2(std::move(s)); // moved -> s is empty now
    std::cout << s << std::endl;

    return 0;
}

Мое объяснение состоит в том, что в первом случае (Player1), name, который является lvalue типа std::string, на самом деле копируется до вызова ctor m_name, затем std::move воздействует на копию, поэтому в конце копия становится пустой и ее содержимое перемещается до m_name, используя ход ctor. Вот почему исходный аргумент s остается нетронутым. Это правильно?

Во втором случае непонятно: std::move преобразует параметр lvalue в эталонное значение r и оттуда что происходит? В этом случае аргумент s после вызова является пустым.

1 Ответ

4 голосов
/ 10 января 2020

Всегда создается новый std::string для заполнения аргумента name до вызова Player(std::string name).

Разрешение перегрузки определяет, будет ли вызываться копия ctor или ctor с перемещением std::string.

Случай 1: Player player1(s);

Новая строка создается копия ctor с подписью basic_string( const basic_string& other );, потому что 's' было lvalue.

Общая сумма операции, которую вы платите, составляет 1 перемещение и 1 копирование конструкций строки:

  1. Один экземпляр ctor, для name arg к ctor
  2. Один ход ctor, для m_name члена класса

Случай 2: Player player2(std::move(s));

Новая строка создается ctor хода для std::string с подписью basic_string( basic_string&& other ) noexcept;

Во втором случае вы вызываете std::move, что приводит к преобразованию s в rvalue-ссылку. std::string имеет 2 конструктора, один из которых принимает const std::string&, другой - std::string&&. Ссылка rvalue может связываться как с ссылкой lvalue, так и с ссылкой rvalue, но версия ссылки rvalue лучше подходит, поэтому она будет выбрана.

Общая сумма операции, которую вы платите, составляет 2 конструкции перемещения строки:

  1. Один ход ctor, для аргумента name в ctor
  2. Один ход ctor, для m_name члена класса

Обратите внимание, что, как отмечают @aschepler и @underscore_d, ctor хода std::string не нуждается в очистке строки источника , Не следует зависеть от этого поведения, так как оно не гарантировано и зависит от того, как реализован ctor перемещения для строк.

...