static_cast для ссылок на r-значение и std::move меняют свой аргумент при инициализации

Следующий простой код показывает, что static_cast к ссылочному типу r-value и std::move могут изменить свой входной аргумент (здесь переменная inupt) в операторе инициализации в зависимости от типа инициализируемого объекта. Может кто-нибудь объяснить такое поведение?

Я, по крайней мере, рад, что static_cast и std::move ведут себя одинаково, поскольку std::move использует static_cast под капотом.

#include <iostream>
#include <string>

int main() {

   {
      std::string input("hello");
      std::string&& result = static_cast<std::string&&>(input);
      std::cout << "cast case 1: input: " << input << " result: " << result << std::endl; // prints: cast case 1: input: hello result: hello
   } 

   {
      std::string input("hello");
      std::string result = static_cast<std::string&&>(input);
      std::cout << "cast case 2: input: " << input << " result: " << result << std::endl; // prints: cast case 2: input:  result: hello
   }

   {
      std::string input("hello");
      static_cast<std::string&&>(input);
      std::cout << "cast case 3: input: " << input << std::endl; // prints: cast case 3: input: hello
   }

   {
      std::string input("hello");
      std::string&& result = std::move(input);
      std::cout << "move case 1: input: " << input << " result: " << result << std::endl; 
      // prints: move case 1: input: hello result: hello
   } 

   {
      std::string input("hello");
      std::string result = std::move(input);
      std::cout << "move case 2: input: " << input << " result: " << result << std::endl; 
      // prints: move case 2: input:  result: hello
   }

   {
      std::string input("hello");
      std::move(input);
      std::cout << "move case 3: input: " << input << std::endl; 
      // prints: move case 3: input: hello
   }

}

person Ahmad S    schedule 24.07.2019    source источник
comment
Это именно то, что делает конструкция перемещения: потенциально захватывает что-либо из исходного объекта, если это помогает с оптимизацией или требуется семантикой.   -  person Quentin    schedule 24.07.2019
comment
Я бы предложил stackoverflow.com/questions/3413470/ и/или stackoverflow.com/questions/3106110/ как дубликат, потому что чтение там должно объяснить все эти тестовые примеры.   -  person Max Langhof    schedule 24.07.2019
comment
Обратите внимание, что этот эксперимент нельзя использовать для вывода о том, что перемещение не имело место, поскольку не гарантируется, что перемещено-из std::string будет пустым. Вам нужно будет использовать что-то вроде std::unique_ptr, чтобы знать наверняка.   -  person Brian Bi    schedule 24.07.2019
comment
Возможный дубликат Что такое семантика перемещения?   -  person L. F.    schedule 25.07.2019


Ответы (2)


Поведение, которое вы наблюдаете, неудивительно и имеет смысл.

Когда вы используете

  std::string result = static_cast<std::string&&>(input);

конструктор перемещения вызывается для инициализации result. Имеет смысл, что конструктор перемещения будет перемещать содержимое input в result.

Сравните это с

  std::string&& result = static_cast<std::string&&>(input);

Здесь result не новый объект. Это просто ссылка на значение r для input. Здесь нет ничего, что требовало бы перемещения содержимого input.

person R Sahu    schedule 24.07.2019
comment
Это не объясняет всей истории. Почему input не изменяется после static_cast или не перемещается в случаях 1 и 3? - person Ahmad S; 24.07.2019
comment
@AhmadS В случае 1 вы не создаете новый объект, вы просто храните ссылку (rvalue) на input в result. Так же, как если бы вы написали std::string& result = input;. В случае 3 вы запутались, потому что std::move сам по себе не перемещает объекты, он просто делает их доступными для перемещения. Я бы посоветовал вам прочитать всестороннее введение в семантику движений, потому что это не то, чему можно научиться методом проб и ошибок (хотя я приветствую возможность заняться этим и проверить все самостоятельно). - person Max Langhof; 24.07.2019
comment
@AhmadS, потому что вы только жонглируете ссылками, вы не создаете какой-либо объект, который мог бы двигаться-инициализироваться сам по себе. - person Quentin; 24.07.2019

по крайней мере, static_cast и std::move ведут себя одинаково, поскольку std::move использует static_cast

Не только похоже, но они делают то же самое. std::move — это статическое приведение к ссылке rvalue.

Может кто-нибудь объяснить такое поведение?

  1. result — это ссылка на input. Привязка ссылки не изменяет указанный объект.
  2. Объект инициализируется. Поскольку он инициализируется значением r, используется конструктор перемещения. Согласно документации std::string, объект input остается в неуказанном, но допустимом состоянии, которое может, но не может отличаться от того, из которого он был до перемещения.
  3. Результат броска отбрасывается. Это не имеет побочных эффектов, и input не будет изменено.
person eerorika    schedule 24.07.2019