Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
#1

std::move, rvalue reference - C++

27.04.2013, 18:57. Просмотров 1060. Ответов 6
Метки нет (Все метки)

Здравствуйте! Недавно начал разбираться с новыми способами передачи аргументов. Прочитал около 10 статей, некоторые на русском, некоторые на английском. Но осталось несколько вопросов...
Помогите разобраться.
Допустим есть класс:
C++
1
2
3
4
5
6
class Foo
{
public:
    Foo( vector<string> v): vec( v ) {}
    vector<string> vec;
};
В главной функции я создаю вектор строк и заполняю его данными для того что бы передать его в конструктор (и больше вектор мне не нужен).
C++
1
2
3
4
5
6
7
8
9
int main()
{
    vector<string> s;
    s.push_back("string 1");
    s.push_back("string 2");
    Foo f( move(s) );
    cout << boolalpha << s.empty(); //вывод true - вектор пустой, значит данные переместились
    return 0;
}
Ставиться вопрос: сколько копирований вектора происходит во время выполнения
C++
1
Foo f( move(s) );
Одно копирование? move(s) переместил содержимое в параметр конструктора v, а после из v содержимое скопировалось в член класса vec.

И еще взгляните на почти аналогичный код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo
{
public:
    Foo( vector<string> v): vec( move(v) ) {} //сюда я добавил move
    vector<string> vec;
};
 
int main()
{
    vector<string> s;
    s.push_back("string 1");
    s.push_back("string 2");
    Foo f( s );
    cout << boolalpha << s.empty(); //на выводе false, то есть было два копирования (из s в v и из v в vec)
    return 0;
}
И такой вариант:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <utility>
#include <vector>
 
using namespace std;
 
class Foo
{
public:
    Foo( vector<string> v): vec( move(v) ) {} //добавил move
    vector<string> vec;
};
 
int main()
{
    vector<string> s;
    s.push_back("string 1");
    s.push_back("string 2");
    Foo f( move(s) ); //добавил move
    cout << boolalpha << s.empty(); //на выводе true
    return 0;
}
То есть, в последнем варианте не было копирования вообще?
Компилятор MinGW 4.7.3
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.04.2013, 18:57     std::move, rvalue reference
Посмотрите здесь:

[C++11] move\rvalue ref semantic - C++
Перегрузил оператор присвоения используя move\rvalue ref semantic. /** * Copy operator * @param rhs Right hand side...

Rvalue reference - C++
#include &lt;iostream&gt; std::string get_string() { return std::string(&quot;12345&quot;); } int main() { std::string const&amp; str =...

Rvalue reference and lambda - C++
void foo(A&amp;&amp; a) { auto l = () {}; //a? } Как передать в лямбду rvalue ref как просто ссылку? Чтобы потом использовать...

Rvalue reference. Что происходит в коде? - C++
В консоли пусто. Но &quot;worked&quot; выводит. Почему? #include &lt;iostream&gt; using std::cout; class Example { public: Example(){ ...

Std::move - C++
Добрый вечер, #include &lt;iostream&gt; using namespace std; class A { private: int x = 10; public: A(int q){ x = q; }

std::move() - C++
Есть ли разница между следующими вещами: A = std::move(B); // and std::copy(B.begin(), B.end(), A.begin()); B.clear();

Optional и std::move - C++
добрый день. разбираясь в исходниках optional'а из gcc, я понял, что там нигде не делается инвалидным только что перемещенный объект. ...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1608 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,927
Завершенные тесты: 1
27.04.2013, 19:14     std::move, rvalue reference #2
Цитата Сообщение от Olivеr Посмотреть сообщение
Одно копирование? move(s) переместил содержимое в параметр конструктора v, а после из v содержимое скопировалось в член класса vec.
move никуда ничего не переместил, потому что конструктор принимает не rvalue reference, а копию. Так что копирование выполняется дважды.
Цитата Сообщение от Olivеr Посмотреть сообщение
То есть, в последнем варианте не было копирования вообще?
Во втором и третьем вариантах выполняется копирование в параметр (оно выполняется всегда, потому что это указано в описании конструктора, и никакой move этого не изменит), а затем эта копия перемещается в vec.

Добавлено через 1 минуту
Как делать конструктор с перемещением:
C++
1
2
3
4
5
6
class Foo
{
public:
    Foo( vector<string>&& v): vec( move(v) ) {}
    vector<string> vec;
};
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
27.04.2013, 19:25  [ТС]     std::move, rvalue reference #3
Цитата Сообщение от Nick Alte Посмотреть сообщение
C++
1
2
3
4
5
6
class Foo
{
public:
    Foo( vector<string>&& v): vec( move(v) ) {}
    vector<string> vec;
};
В таком случае будет прямое перемещение? Не будет копирования?

Я не просто так передавал по значению. Я видел много раз, что люди так делают. Например такой класс:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Book {
public:
  Book(std::string title,
       std::vector<std::string> authors,
       size_t      pub_day
       std::string pub_month,
       size_t      pub_year)
    : _title    (std::move(title)),
      _authors  (std::move(authors)),
      _pub_day  (pub_day),
      _pub_month(std::move(pub_month)),
      _pub_year (pub_year)
     {}
 
  // ....
  // ....
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
std::string & toUpper(std::string & s)
{
  std::transform(s.begin(), s.end(), s.begin(), toupper);
  return s;
}
const std::string & January()
{
  static std::string jan("January");
  return jan;
}
int main(void)
{
  std::vector<std::string> authors { "A", "B", "C" };
  Book b1("Book1", authors, 1, "Jan", 2012);
 
  size_t year = 2012
  Book b2("Book2", { "A", "B", "C" }, 1, "Jan", year);
 
  std::string month = "Mar";
  Book b3("Book3", { "Author" }, 1, toUpper(month), 2012)
 
  Book b4("Book4", { "Author" }, 1, January(), 2012);
 
  std::string book = "Book";
  Book b5(std::move(book), std::move(authors), 1, std::move(month), year);
 
  Book b6("Book", { "Author" }, 1, "Jan", 2012);
}
И объяснения:
In case of b1, except for authors all other parameters are copied and moved once.
In case of b2, all strings and vectors are copied and moved once. That's what matters.
In case of b3, toUpper returns an string reference; everything else copied and moved only once.
In case of b4, January returns a const string reference; everything else copied and moved once.
In case of b5, strings are vector are moved as expected and in fact the b5 object the local parameters are created using move-constructor and moved again into the data member. Hence the object is created without any deep copies (like zero-copy).
Nick Alte
Эксперт С++
1608 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,927
Завершенные тесты: 1
27.04.2013, 19:43     std::move, rvalue reference #4
Цитата Сообщение от Olivеr Посмотреть сообщение
В таком случае будет прямое перемещение? Не будет копирования?
Да. Разумеется, при вызове конструктора в том примере использование move тоже будет необходимо. А вот созданный прямо в месте вызова вектор можно и без move.

В приведённом примере с Book все параметры копируются. Эти копии уже и перемещаются в члены класса. Возможно, это не очень годный пример. Рассказ про zero-copy without deep copies - наглая беззастенчивая ложь.
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
27.04.2013, 19:58  [ТС]     std::move, rvalue reference #5
Спасибо за ответ.
Кстати, по времени выполнения эта два варианты одинаковы: (0.7 сек)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo
{
public:
    Foo( vector<string> v): vec( move(v) ) {}
    vector<string> vec;
};
 
int main()
{
    vector<string> s(10000000,"text-text-text!");
    cout << "vector constructed!";
    Foo f( move(s) );
    cout << boolalpha << s.empty();
    return 0;
}
и
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <utility>
#include <vector>
 
using namespace std;
 
class Foo
{
public:
    Foo( vector<string> &&v): vec( move(v) ) {}
    vector<string> vec;
};
 
int main()
{
    vector<string> s(10000000,"text-text-text!");
    cout << "vector constructed!";
    Foo f( move(s) );
    cout << boolalpha << s.empty();
    return 0;
}

Цитата Сообщение от Nick Alte Посмотреть сообщение
А вот созданный прямо в месте вызова вектор можно и без move.
Вот так?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <utility>
#include <vector>
 
using namespace std;
 
class Foo
{
public:
    Foo( vector<string> &&v): vec( v ) {} //убрал move
    vector<string> vec;
};
 
int main()
{
    vector<string> s(10000000,"text-text-text!");
    cout << "vector constructed!";
    Foo f( move(s) );
    cout << boolalpha << s.empty();
    return 0;
}
Компилятор не ругается, но время выполнения 1.4 секунды...

Если делать так:
C++
1
2
3
4
5
6
    Foo( vector<string> &&v): vec( move(v) ) {}
...
...
...
//вызов
Foo f(s); //ошибка: cannot bind 'std::vector<std::basic_string<char> >' lvalue to 'std::vector<std::basic_string<char> >&&'|
Nick Alte
Эксперт С++
1608 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,927
Завершенные тесты: 1
28.04.2013, 09:42     std::move, rvalue reference #6
Цитата Сообщение от Olivеr Посмотреть сообщение
Вот так?
Нет, вот так:
C++
1
Foo f(vector<string> {"Foo", "bar"});
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.04.2013, 11:39     std::move, rvalue reference
Еще ссылки по теме:

Std::move stl-алгоритм - C++
здравствуйте, есть такой код: std::string his = &quot;what the work ?&quot;; std::istringstream isg(his); ...

Немного не понимаю std::move - C++
Здравствуйте, я немного не понимаю работу кода на 150-155 строках здесь: #include &lt;iostream&gt; #include &lt;memory&gt; #include...

Func(std::move(.) копирует ? - C++
Здравствуйте, имеется следующий код: void foo(std::vector&lt;int&gt;&amp;&amp; v) { std::cout &lt;&lt; &quot;vector is taken&quot; &lt;&lt; std::endl; ...

Error: 'move' is not a member of 'std' - C++
Как бороться с этой гогой?

Не срабатывает move конструктор std::unique_ptr - C++
Всем привет! Битый час не пойму почему в списке захвата компилятор ругается на удаленный копирующий конструктор unique_ptr, если я его...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
28.04.2013, 11:39  [ТС]     std::move, rvalue reference #7
Цитата Сообщение от Nick Alte Посмотреть сообщение
Нет, вот так:
C++
1
Foo f(vector<string> {"Foo", "bar"});
А это понятно.
Так как vector<string> {"Foo", "bar"} является временным объектом, то не нужно убеждать компилятор (с помощью move), что это rvalue, как это было в предыдущих примерах.
Yandex
Объявления
28.04.2013, 11:39     std::move, rvalue reference
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru