LINUX.ORG.RU

c++ move constructor

 


0

1

Кто-нибудь может мне объяснить, почему здесь вызван move constructor?

#include <iostream>
using namespace std;

class ToBeMoved {
public:
    ToBeMoved() = default;
    ToBeMoved(const ToBeMoved& tbm)
    {
        cout << "ToBeMoved::copy_ctor" << endl;
    }
    ToBeMoved(ToBeMoved&& tbm)
    {
        cout << "ToBeMoved::move_ctor" << endl;	
    }
    ToBeMoved& operator=(const ToBeMoved& tbm)
    {
        cout << "ToBeMoved::copy_operator=" << endl;
    }
    ToBeMoved& operator=(ToBeMoved&& tbm)
    {
        cout << "ToBeMoved::move_operator=" << endl;
    }
};

void f_rval(ToBeMoved&& tbm)
{
    cout << "f_rval" << endl;
}

void f(ToBeMoved tbm)
{
    f_rval(move(tbm));
}

int main(int argc, char *argv[])
{
    ToBeMoved tbm;
    f(move(tbm));
    return 0;
}

Т.е. я вроде понимаю, что происходит, tbm был «перенесен» в параметр f(), но ведь f() задекларирована так, что принимает tbm by value, почему в этом случае не был вызван copy constructor, несмотря на move?

★★

Последнее исправление: dissident (всего исправлений: 1)

ведь f() задекларирована так, что принимает tbm by value, почему в этом случае не был вызван copy constructor, несмотря на move?

А почему должен был быть вызван copy constructor? Как на это влияет «by value»?

utf8nowhere ★★★
()

f внутри main должна получить экземпляр ToBeMoved tbm по значению, для этого его нужно сконструировать. Конструируется этот новый экземпляр из ToBeMoved&&, который возвращает std::move() (std::move() возвращает rvalue ссылку, причем безымянную, поэтому она является rvalue).

А теперь вопрос, какой конструктор создает экземпляр ToBeMoved, передаваемый в функцию f(), из rvalue ToBeMoved&& ??? Подсказка в f() передается ее собственный экземпляр ToBeMoved, никак не связанный с ToBeMoved tbm в функции main().

P.S. Не каждая rvalue ссылка является rvalue значением. Если у нее есть имя - то она lvalue, если безымянная (например, возвращаемая из std::move() - тогда rvalue).

anonymous
()

И вдогонку лучшая статья про perfect forwarding и rvalue references.

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

Только учитывай, что «универсальные ссылки» решено называть «передающими ссылками» (forwarding references).

Еще ссылка на мой комментарий про rvalue references (близко к твоему вопросу, но не совсем про то же) https://habrahabr.ru/post/343622/#comment_10548024

anonymous
()

Ну и, наконец, из operator= нужно что-то возвращать. Там return нужен.

anonymous
()
Ответ на: комментарий от anonymous

clang (и я тоже) считает, что это lvalue типа int.

Во-первых, я не понял, с чем конкретно ты не согласен (или согласен). Или ты всерьез считаешь, что int&& super_ref - это переменная типа int?

Насколько я понимаю, clang считает, что super_ref - это lvalue (или xvalue) типа int&&, ссылающийся на временную переменную типа int.

anonymous
()
Ответ на: комментарий от anonymous

Или ты всерьез считаешь, что int&& super_ref - это переменная типа int?

Я всерьёз считаю, что super_ref в выражениях имеет тип int.

Насколько я понимаю, clang считает

В AST написано в формате 'тип' value_category [дополнительная информация]. И про выражение в 5-й строке кода

int main()
{
    int&& super_ref = 10;

    super_ref;
}
clang говорит что это 'int' lvalue

anonymous
()
Ответ на: комментарий от anonymous

clang говорит что это 'int' lvalue

clang это говорит про строку 5, в которой написано ВЫРАЖЕНИЕ DeclRefExpr (взять значение super_ref, ничего с ним не делать и вернуть его как значение выражения, которое тут же забывается). Что-то типа (super_ref + 2);, только без +2. На самом деле, тут я не очень разбираюсь, потому что на практике такое выражение бесполезно, а потому я с такими ситуациями не разбирался глубоко. Почему значение этого выражения lvalue, я тоже не в курсе.

anonymous
()
Ответ на: комментарий от anonymous

clang это говорит про строку 5, в которой написано ВЫРАЖЕНИЕ

Ну да. Речь ведь про lvalue/rvalue, поэтому мы говорим про выражения. Говорить, является ли объявление переменной lvalue или rvalue — бессмысленно, это свойства выражений.

На самом деле, тут я не очень разбираюсь, потому что на практике такое выражение бесполезно, а потому я с такими ситуациями не разбирался глубоко.

Лол. При чём тут «на практике» или «бесполезно». Если бы там было f(super_ref), то подвыражение super_ref по прежнему будет DeclRefExpr 'int' lvalue .... Я просто взял минимальное выражение, состоящее из super_ref.

DeclRefExpr — это внутренняя кухня clang-а по классификации выражений («выражение, ссылающееся на объявление»). В общем, неважно, как его обозвали. Я просто хотел обратить внимание, что тип не int&&, а int.

Почему значение этого выражения lvalue, я тоже не в курсе.

?????

Ты вроде это сам объяснял выше.

anonymous
()
Ответ на: комментарий от anonymous

Говорить, является ли объявление переменной lvalue или rvalue — бессмысленно

угу

потому что оно всегда lvalue

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.