Передача по значению / ссылке / r-значению с аргументом std :: move (str) - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть следующий код:

//void func(const std::string &&i){
//void func(const std::string &i){
void func(const std::string i){
  std::string val{i};
}

int main() 
{ 
  std::string d = "asdf";
  func(std::move(d));
  std::cout << d << std::endl;
} 

Когда i является передачей по значению, d становится пустым, но d сохраняет свою форму, если мы передаем по ссылке или по ссылке r-value. Может ли кто-нибудь объяснить, что происходит?

Я понимаю, что std::move на самом деле ничего не перемещает, но делает переменную, которую он принимает, подвижной, приводя ее к значению x.

Кроме того, почему код в текущем состоянии компилируется, если d приведен к значению x? func в настоящее время настроен на прием по аргументам значения, а не по ссылке rvalue.

Ответы [ 2 ]

3 голосов
/ 21 апреля 2020

Когда i передается по значению, d становится пустым,

Если быть точным, d будет в каком-то допустимом состоянии, не указанном в стандарте C ++. Пустой - одна из возможностей.

std::move сам по себе никогда не вызывает непосредственный вызов конструктора перемещения. Привязка ссылки rvalue к объекту также не вызывает непосредственного вызова конструктора перемещения.

Только инициализация объекта с неконстантным значением r приведет к перемещению аргумента. В этом примере std::string i инициализируется с неконстантным значением r, и будет вызван конструктор перемещения.

В качестве причины, почему код в текущем состоянии компилируется, если d приведен к x-значение?

Поскольку тип имеет (не удаленный) конструктор перемещения. Следовательно, аргумент может быть инициализирован из значений r.

Я думал, что если бы у нас был std :: string i, была сделана копия ссылки на rvalue.

std::string i не является ссылкой. Это переменная типа std::string, и поэтому с ней связан объект типа std::string. Этот объект инициализируется с выражением, которое передается в функцию в качестве аргумента.

Кроме того, если я увижу, что вывод d по-прежнему такой же, как до применения std :: move, что делает в данном случае это означает?

Если вы вызываете некомментированную версию функции со значением r, то аргумент будет перемещен из. Если значение такое же, как было, то это просто означает, что значение такое же. Вы не можете предполагать, что значение будет таким же или не будет таким же.

Означает ли это, что d все еще занимает место, которое изначально занимало?

Предполагая, что под "пробелом" вы подразумеваете хранилище, в котором находится переменная, тогда, конечно, оно все еще занимает то же хранилище. Адрес объекта никогда не меняется в течение всего времени существования объекта.

0 голосов
/ 21 апреля 2020
void func(const std::string &&i)

Эта подпись ничего не будет перемещать, поскольку ссылка на объект const. Удалите const, и все заработает. Но только если вы std::move параметр i снова внутри функции. Это потому, что все, что имеет имя, является lvalue, независимо от того, был ли параметр объявлен как & или &&. См. этот ответ .

void func(const std::string &i)

Это скопирует, как вы, вероятно, уже знаете. Тем не менее, он ведет себя так же, как и предыдущий, в том смысле, что если вы уроните const и выполните std::move( i ) внутри функции, он на самом деле будет двигаться. Это потому, что, как вы заметили, move - это приведение, и компилятор будет слушать вас и делать именно то, что вы говорите, когда делаете приведение, независимо от того, что вы намеревались.

void func(const std::string i)

Это перемещается в вашем пример, потому что здесь i - совершенно новая строка. Внешняя строка d перемещается в i. Тем не менее, вам все равно придется сбросить const и использовать std::move( i ), если вы хотите переместить i в val.

...