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

C++

Войти
Регистрация
Восстановить пароль
 
elch10
38 / 21 / 4
Регистрация: 27.04.2015
Сообщений: 164
Завершенные тесты: 2
#1

Lvalue и rvalue - C++

30.06.2016, 13:27. Просмотров 362. Ответов 5
Метки нет (Все метки)

Какая выгода использования rvalue? Допустим есть такой класс
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A
{
public:
    A() = default;
    void setName(const std::string& name)
    {
        m_Name = name;
    }
 
    void setName(std::string&& name)
    {
        m_Name = std::move(name);
    }
private:
    std::string m_Name;
};
и main
C++
1
2
3
4
5
6
7
8
int main()
{
    A a;
    std::string name{"another name"};
    a.setName("New name");//№1
    a.setName(name);//№2
    return 0;
}
Какая выгода использования rvalue? Ведь при использовании по ссылке, не вызываются никакие конструкторы копирования и т.д. И мы просто копируем данные. А при перемещении мы копируем из источника, а потом удаляем данные из источника. Так и какая здесь выгода, если удаление строки и так произойдёт, только сразу же после выхода из функции. Я имею ввиду что если мы уберём функцию с rvalue
C++
1
2
3
4
void setName(std::string&& name)
    {
        m_Name = std::move(name);
    }
и будем использовать lvalue версию с rvalue, вот так
C++
1
a.setName("New name");
Или я что то не понял?
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.06.2016, 13:27
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Lvalue и rvalue (C++):

Значения Lvalue и Rvalue - C++
Здравствуйте. В данной ссылке https://msdn.microsoft.com/ru-ru/library/f90831hc.aspx приведен пример int main() { int...

Вывод типа, универсальные ссылки, cannot bind lvalue to && и другие - C++
Доброго дня, товарищи. Вот код: Вот отчет компиля: Объясните мне, пожалуйста, где я не прав. Каким образом константный lvalue литерал...

E2277 Lvalue required - C++ Builder
что бы значила такая ошибка? вылетает при попытке присвоить массиву char-ов значение ячейки TStringGrid (с использованием c_str())

Ошибка E2277 Lvalue required - C++ Builder
У меня есть структура struct equip { int id; char name; float price; };и массив equip list;мне нужно...

[C++ Error] E2277 Lvalue required - C++ Builder
Здравствуйте помоги разобратся что за ошибка //--------------------------------------------------------------------------- ...

char в complex<double>: Lvalue required - C++ Builder
Здравствуйте. Пытаюсь перегнать массив формата char в complex&lt;double&gt; (работаю с библиотекой complex). char * massiv1 = new...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
avgoor
885 / 520 / 112
Регистрация: 05.12.2015
Сообщений: 1,467
30.06.2016, 15:36 #2
Цитата Сообщение от elch10 Посмотреть сообщение
А при перемещении мы копируем из источника
При перемещении мы не копируем, а перемещаем (просто перекидываем указатели на данные).
elch10
38 / 21 / 4
Регистрация: 27.04.2015
Сообщений: 164
Завершенные тесты: 2
30.06.2016, 17:40  [ТС] #3
avgoor, а тогда зачем move? можем ли мы просто написать
C++
1
m_Name = name;
? или у него какой-то свой межанизм работы?
avgoor
885 / 520 / 112
Регистрация: 05.12.2015
Сообщений: 1,467
30.06.2016, 19:18 #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от elch10 Посмотреть сообщение
или у него какой-то свой межанизм работы?
Он просто возвращает rvalue-ссылку на переданный объект.
Теперь, почему он необходим.
Если в вашей функции завести еще одну rvalue-ссылку:
C++
1
2
3
4
void SetName(std::string&& s)
{
    std::string&& ref=s;//Ошибка
...
Получим ошибку компиляции, потому что не смотря на то, что s имеет тип rvalue-ссылки, участвуя в выражении, он - lvalue (т.к. имеет имя "s").

Чтоб избежать ошибки нужно явно откастовать к &&, что и делает std::move, т.е.
std::string&& ref=(std::string&&)s; и std::string&& ref=std::move(s); - эквивалентны.

Какой operator= вызовется?
C++
1
2
3
4
5
void setName(std::string&& name)
{
    m_Name = std::move(name);//Вызовется operator=(string&&)
    m_Name = name;//Вызовется operator=(string&), т.к. name - lvalue
}
Надеюсь понятно.
ASCII
90 / 62 / 10
Регистрация: 15.12.2013
Сообщений: 399
Завершенные тесты: 2
18.07.2016, 02:53 #5
elch10,
C++
1
2
3
4
5
6
7
8
int main()
{
* * A a;
* * std::string name{"another name"};
* * a.setName("New name"); // не №1, а №2
* * a.setName(name); // не №2, а №1
* * return 0;
}
1) При передаче строки "New name", мы провоцируем создание временного объекта (на практике это не всегда так), которое классифицируется как rvalue
2) Выражение name - это идентификатор объекта, а любой идентификатор объекта, это lvalue выражение

http://rextester.com/BTUZU14864

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <chrono>
 
class Example
{
public:
 
    // default ctor
    Example() : pointer_{::new int[100500]} { }
 
    // copy ctor
    Example(Example const& other) : pointer_{::new int[100500]}
    {
        // в данном примере, лучше юзать std::memcpy, т.к. это интринсик
        // но на месте int, может быть любой другой класс
        // внимание тут надо акцентировать на том, что тут происходит копия
 
        for(std::size_t i = 0; i < 100500; ++i)
        {
            pointer_[i] = other.pointer_[i];
        }
    }
 
    // move ctor
    Example(Example&& other) : pointer_{other.pointer_}
    {
        // а тут надо акцентировать внимание на следующем:
        // 1) раз вызывается конструктор перемещения, значит переданный объект
        // является временным, в большинстве случаев (может быть и не временным, если вызвать std::move)
        // 2) значит мы можем просто забрать указатель на хранимые в нем данные и пропустить копирование
 
        other.pointer_ = nullptr;
    }
 
    ~Example() { ::delete pointer_; }
 
private:
    int* pointer_;
};
 
void call_copy_ctor(Example ex)
{
    // просто, чтобы заглушить warning от компилятора
    (void)ex;
 
    /* создается объект ex, с помощью копирования, затем уничтожается, исходный объект не портится */
}
 
void call_move_ctor(Example&& ex)
{
    // просто, чтобы заглушить warning от компилятора
    (void)ex;
 
    /* создается объект ex, с помощью перемещения, затем уничтожается, исходный объект обнуляется */
}
 
int main()
{
    Example arr[1000];
 
    auto start = std::chrono::high_resolution_clock::now();
    for(std::size_t i = 0; i < 1000; ++i)
    {
        call_copy_ctor(arr[i]);
    }
    auto end = std::chrono::high_resolution_clock::now();
 
    std::cout << "Time for copy: ";
    std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
    std::cout << " nanoseconds." << std::endl;
 
    start = std::chrono::high_resolution_clock::now();
    for(std::size_t i = 0; i < 1000; ++i)
    {
        call_move_ctor(std::move(arr[i]));
    }
    end = std::chrono::high_resolution_clock::now();
 
    std::cout << "Time for move: ";
    std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
    std::cout << " nanoseconds." << std::endl;
 
    return 0;
}
То есть rvalue ссылки, благодаря тому, какие объекты они описывают, позволяют создавать конструкторы перемещения, которые, исходя из того, что объект rvalue (то есть временный), просто забирает указатель на данные, без копирования, а это сильно снижает нагрузку. Взгляните на время выполнения копирования и на время выполнения перемещения http://rextester.com/UXAEG92502
hoggy
6545 / 2725 / 471
Регистрация: 15.11.2014
Сообщений: 6,013
Завершенные тесты: 1
18.07.2016, 10:38 #6
Цитата Сообщение от elch10 Посмотреть сообщение
Ведь при использовании по ссылке, не вызываются никакие конструкторы копирования и т.д. И мы просто копируем данные.
что бы ничего не копировать, а сразу переместить.
копирование - долгая операция.

rvalue позволяют "ограбить" (опустошить) объект,
захапав все его данные без всякого копирования.

то есть исходный объект окажется после этого опустошенным.
ну а принимающий объект - с готовенькими данными.

ну а поскольку временные объекты все равно не жильцы,
то их можно смело опустошать,
и экономить на дорогущем копировании.

вот таким образом, rvalue работает с временными объектами,
и позволяет их грабить.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.07.2016, 10:38
Привет! Вот еще темы с ответами:

AnsiString to Char или Lvalue required - C++ Builder
Добрый день, форумчане. Помогите разобраться, поскольку сам я нуб. Есть char m_sComPort и туда нужно вставить значение com-порта из...

Lvalue required. Добавление строк в Memo - ввод книги, вывод книги по ID. - C++ Builder
Вроде библиотечной программы. Ввод книги. Вывод книги по ID. #include &quot;Unit1.h&quot; ...

Rvalue и lvalue ссылки - C++
Здравствуйте, что расскажите, пожалуйста что такое lvalue и rvalue ссылки и с чем их едят, где можно использовать, и чем отличается...

Что такое rvalue и lvalue - C++
как понимать эти штуки?


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
18.07.2016, 10:38
Ответ Создать тему
Опции темы

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