Назначение rvalue ссылок при назначении строки - PullRequest
0 голосов
/ 27 января 2019

Я узнаю о ссылках на rvalue, и мой мозг, вероятно, повсюду.Но я хотел проверить ссылки на std :: move и rvalue, и ниже приведен фрагмент кода

string s1 = "hello";
{
    string&& s2 = std::move(s1);
    cout << s2 << endl;
}

cout << s1 << endl;

Вывод одинаковый в обоих случаях."привет"

Я надеялся, что внутри блока при создании s2 он вызвал бы оператор присваивания перемещения, таким образом убедившись, что s1 ни на что не указывал, но этого не произошло.

Мой разум заключается в том, что строка содержит указатель на символ внутри нее, поэтому, когда вызывается указатель перемещения, она перемещает выделение памяти из Таким образом, когда я перехожу с s1 на s2, печать s1 должна вызывать проблемы.

Что я сделал не так в моем понимании.

Ответы [ 2 ]

0 голосов
/ 27 января 2019

С одной стороны,

string&& s2 = std::move(s1);

вовсе не является заданием;это инициализация.

И это инициализация ссылки, а не объекта.В вашей программе есть только один std::string с именем s1.Поскольку вы объявили s2 как ссылку, она ссылается на какой-то другой объект - здесь это s1.Так что никакой конструктор перемещения или оператор присваивания перемещения вообще не нужно вызывать, и s1 нельзя изменить.

Если вы вместо этого напишите

string s2 = std::move(s1);

, это фактически создаствторой std::string объект с именем s2.Он инициализируется с помощью конструктора перемещения.

Или, если = используется на ранее объявленном объекте, чтобы не вводить инициализатор сразу после объявления, тогда это истинное присваивание:

string s2;
s2 = std::move(s1);

Здесь s2 сначала создается с помощью конструктора std::string по умолчанию, а затем изменяется с помощью std::string оператора присваивания перемещения.

Но обратите внимание, что после std::string конструктор перемещения или оператор присваивания перемещениясодержимое объекта «отъехал» не указано .В некоторых случаях Стандарт говорит точно, что будет делать операция перемещения, часто делая перемещенный объект пустым.Но если не указано иное, он говорит только о том, что объект находится в «допустимом, но неопределенном состоянии».И std::string не добавляет никаких особых требований, поэтому результатом является неопределенное состояние.Поэтому печать s1 после этого может привести к чему-либо.(Практически говоря, если в реализации std::string используется оптимизация малых строк, вы можете обнаружить, что s1 не был изменен.)

0 голосов
/ 27 января 2019

s2 по-прежнему является ссылкой, это означает, что никакой другой конструктор или оператор присваивания не был вызван в вашем коде.Вы можете использовать s2 для вызова конструктора перемещения или назначения перемещения.В этом конструкторе произойдет волшебство перемещения (даже если старая строка все еще может содержать исходный текст после этого).

string s1 = "hello";
string&& s2 = std::move(s1);  // s2 is a reference
string s3 = std::move(s2);    // now we moved
...