Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.70/50: Рейтинг темы: голосов - 50, средняя оценка - 4.70
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499

Конструктор перемещения

30.03.2015, 23:08. Показов 10538. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, пытаюсь уже некоторое время разобраться с move-семантикой. Честно говоря возникли сложности сразу же. Помогите пожалуйста разобраться.
вот например такой элементарный код:

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
class Base {
public:
    Base(int i){
        cout<<"create Base"<<endl;
    }
    Base(const Base& a){
        cout<<"create copy Base"<<endl;
    }
    Base(Base&& a){
        cout<<"create move Base"<<endl;
    }
    ~Base() {
        cout<<"deleting Base"<<endl;
    }
    Base reg(Base a){
        return a;
}
};
 
int main()
{
int i=1;
    {
        Base a(i);
        a.reg(a);
    }
    return 0;
}
вывод:

create Base
create copy Base
create move Base
deleting Base
deleting Base
deleting Base

если закомментить конструктор перемещения, то будет:

create Base
create copy Base
create copy Base
deleting Base
deleting Base
deleting Base

Вопрос: почему этот move-конструктор вызывается, т.е. что он и куда перемещает?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
30.03.2015, 23:08
Ответы с готовыми решениями:

Конструктор перемещения
Правильно написан конструктор, значения в right нужно обнулять или не нужно? class Test { private: int count_; // Кол-во...

Конструктор перемещения
Здравствуйте. У меня есть такой класс: class Organization { char *name; int year, staffQual; double salaryFund;

C++11 Конструктор перемещения
Добрый день. Решил тут познакомится с конструктором перемещения, и сразу протестировал кое-что. Конструктор перемещения просто изымает...

17
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
30.03.2015, 23:15
RVO / NRVO
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
30.03.2015, 23:27  [ТС]
rikimaru2013, можете пояснить? честно говоря не понял ничего
0
2444 / 1842 / 406
Регистрация: 15.12.2013
Сообщений: 8,243
30.03.2015, 23:33
Цитата Сообщение от tapochka Посмотреть сообщение
можете пояснить? честно говоря не понял ничего
тогда может лучше к учебникам?
а пока ссылки по теме:
http://habrahabr.ru/post/183454/
http://stackoverflow.com/quest... -semantics
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
30.03.2015, 23:46
Лучший ответ Сообщение было отмечено tapochka как решение

Решение

http://rextester.com/TLW95742


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
#include <iostream>
using namespace std;
 
struct Base 
{
    Base(int i)      { cout<<"create Base"     <<endl; }
    Base(const Base&){ cout<<"create copy Base"<<endl; }
    Base(Base&& a)   { cout<<"create move Base"<<endl; }
    ~Base()          { cout<<"deleting Base"   <<endl; }
};
 
 
Base RVO()  { return Base(1); }
 
Base NRVO() { Base b(1); return b; }
 
int main()
{
    cout <<" ============= RVO\n";
    {
        // мы не наблюдаем никаких копирующих или перемещающих конструкторов
        Base b( RVO() );
    }
    
    cout <<" ============= NRVO\n";
    {
        // мы не наблюдаем никаких копирующих или перемещающих конструкторов
        Base b( NRVO() );
    }
    
    cout <<" ============= copy\n";
    {
        // мы наблюдаем конструктор копии
        Base a(1);
        Base b = a;
    }
    
    cout <<" ============= move\n";
    {
        Base a(1);
        
        // мы сообщаем компилятору, что объект a нам больше не нужен, 
        // и его можно смело переместить
        // в результате наблюдаем конструктор перемещения.
        
        // ВАЖНО: после перемещения объект a должен быть uncpecified
        // что означает: состояние перемещенного объекта может быть любым, 
        // но он должен быть работоспособным.
        Base b = std::move(a);
    }
    
    
    return 0;
}
2
 Аватар для Zazy
47 / 47 / 23
Регистрация: 14.04.2013
Сообщений: 188
31.03.2015, 00:10
Студия 2013
Миниатюры
Конструктор перемещения  
0
2444 / 1842 / 406
Регистрация: 15.12.2013
Сообщений: 8,243
31.03.2015, 00:29
Цитата Сообщение от Zazy Посмотреть сообщение
Студия 2013
VS12 аналогичный вывод.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.03.2015, 00:42
Цитата Сообщение от Zazy Посмотреть сообщение
Студия 2013
Цитата Сообщение от S_el Посмотреть сообщение
VS12 аналогичный вывод.
если вас смущает, что вы наблюдаете move ctor при NRVO - не переживайте.
NRVO - стандартизированная оптимизация.

от прочих оптимизаций компилятора отличается тем,
что все компиляторы обязаны её поддерживать.

но будучи именно оптимизацией, компиляторы не обязаны её задействовать,
если конфигурация сборки "debug".

просто соберите проект в режиме "release", и все будет ок.
2
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
31.03.2015, 05:42  [ТС]
всем спасибо за ответы, походу надо сначала с rvalue разобраться толком, затем RVO/NRVO, а затем уже с std::move

Добавлено через 1 час 16 минут
согласно http://en.cppreference.com/w/cpp/utility/move
возвращаемое значение std::move имеет тип static_cast<typename std::remove_reference<T>::type&&>(t). То есть в вышеприведенном примере hoggy объект a после std::move(a) становится rvalue-ссылкой(временным объектом) или нет? То есть поэтому у этой переменной после std::move(a) состояние как uncpecified или по другой причине?
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
31.03.2015, 05:49
Цитата Сообщение от tapochka Посмотреть сообщение
То есть поэтому у этой переменной после std::move(a) состояние как uncpecified или по другой причине?
После std::move объект вообще не изменяется. Просто std::move приводит ссылку на объект к rvalue-ссылке
Можете заглянуть в соседнюю тему Std::move
В каком состоянии оставлять объект после перемещения дело 'разработчика', который и определяет, что будет происходить при перемещении. Собственно поэтому и получается
Цитата Сообщение от hoggy Посмотреть сообщение
// ВАЖНО: после перемещения объект a должен быть uncpecified
// что означает: состояние перемещенного объекта может быть любым,
// но он должен быть работоспособным.
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
31.03.2015, 06:06  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
В каком состоянии оставлять объект после перемещения дело 'разработчика', который и определяет, что будет происходить при перемещении. Собственно поэтому и получается
хммм, а что мы можем сделать с объектом при перемещении? не совсем понял
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
31.03.2015, 06:07
Цитата Сообщение от tapochka Посмотреть сообщение
хммм, а что мы можем сделать с объектом при перемещении? не совсем понял
Пройдите по ссылке, там есть небольшой пример.
0
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
31.03.2015, 06:39  [ТС]
в вашем примере если написать так:
C++
1
2
3
4
{
    my_class a("hello");
    my_class b = a;
}
то ведь после второй строки вызывается конструктор копии, а после выхода из скобок два раза вызывается деструктор, т.е. два раза уничтожается m_str. Разве нет? так вроде нельзя делать
0
Неэпический
 Аватар для Croessmah
18144 / 10728 / 2066
Регистрация: 27.09.2012
Сообщений: 27,026
Записей в блоге: 1
31.03.2015, 06:43
Тот код предназначен для показа именно в том виде, в котором показан и не иначе.
Цитата Сообщение от tapochka Посмотреть сообщение
строки вызывается конструктор копии,
внутри создается копия строки
Цитата Сообщение от tapochka Посмотреть сообщение
после выхода из скобок два раза вызывается деструктор
Деструкторы для каждого объекта будут вызваны. m_str в каждом объекте свой и каждый из них содержит адрес своего буфера
Может сначала Вам стоит подтянуть более простые вещи, а не rvalue-reference?
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
31.03.2015, 07:10  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
Деструкторы для каждого объекта будут вызваны. m_str в каждом объекте свой и содержат они каждый арес своего буфера.
Может сначала Вам стоит подтянуть более простые вещи, а не rvalue-reference?
да честно говоря я сам понял, что ерунду какую-то спорол. просто вспомнилась глава из книжки одной, там как раз этот пример был(похожий), но только оказывается специально с ошибкой, когда не был реализован конструктор копии... эх(

Добавлено через 17 минут
теперь я сам ответил на свой вопрос, заданный в самом начале: конструктор перемещения вызывается когда создается rvalue-ссылка, т.е. когда пишем:
C++
1
2
Base a(i);
a.reg(a);
то сначала вызывается конструктор копии когда засовываем объект а в функцию reg, затем reg возвращает временный объект a - и тут он уже как rvalue-ссылка.
а когда пишем:
C++
1
2
Base a(1);
Base b = std::move(a);
то мы насильно делаем объект a rvalue-ссылкой. поэтому тоже вызывается конструктор перемещения.
на сегодня можно идти спать наконец-то...
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.03.2015, 14:47
Лучший ответ Сообщение было отмечено tapochka как решение

Решение

Цитата Сообщение от tapochka Посмотреть сообщение
то мы насильно делаем объект a rvalue-ссылкой. поэтому тоже вызывается конструктор перемещения.
верно.

объект, который изначально был самым обычным lvalue, но насильственно был приведен к rvalue,
стандарт обозвал xvalue

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

различают prvalue и xvalue.

prvalue - это "настоящий rvalue"

пример:

C++
1
2
3
4
5
some foo() { return some(); }
...
 
//результат работы foo  - prvalue
auto obj = foo();
очевидно, что prvalue - ни что иное, как временный объект.
время жизни которого - до конца всего выражения, где он был создан.
то бишь, он - гарантированно не жилец.

это открывает пути для оптимизаций:
если объект не жилец, то его можно смело ограбить,
потому что он все равно сдохнет, и никому уже не нужен.
главное, что бы у него диструктор оставался рабочим.


но для этого нужно как то различать: кто тут временный, а кто не временный.

вот так в с++11 и появился новый тип данных r-value reference,
который мы и наблюдаем в move конструкторах

благодаря чему и стало возможным опустошать временные объекты
---------------------------------------------------------------------

но тогда возникает проблема приведений типов.
ведь технически, мы можем привести обычный lvalue к rvalue.
а значит сделать вид "будто бы у нас тут временный объект".

другими словами, мы можем опустошить объект,
который по факту рождения нефига не временный:


C++
1
2
3
4
5
6
7
// xvalue изначально не является "временным объектом"
// изначально он самый обычный lvalue
std::string xvalue = "hello";
 
std::string lvalue = std::move(xvalue); //<-- мы насильно сделали его rvalue
// в результате произошло опустошение не временного
// а самого обычного объекта
результат насильственного приведения lvalue к rvalue есть xvalue

с точки зрения функций, между prvalue и xvalue разницы нет.
функции не различают что есть prvalue, а что xvalue.
для них они все - rvalue

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

это связанно именно с xvalue, который после опустошения нефига не сдохнет,
и может быть и дальше использован в программе.
2
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
31.03.2015, 17:24  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
это связанно именно с xvalue, который после опустошения нефига не сдохнет,
и может быть и дальше использован в программе.
ему можно присвоить значение я так понимаю... а можно ли еще что-то сделать с ним?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
31.03.2015, 18:09
Цитата Сообщение от tapochka Посмотреть сообщение
ему можно присвоить значение я так понимаю... а можно ли еще что-то сделать с ним?
конечно.

после того, как вы посетили опустошенному объекту новое состояние,
он опять становится самым обычным объектом.

и с ним можно делать все тоже самое, что и с обычным объектом.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.03.2015, 18:09
Помогаю со студенческими работами здесь

Конструктор перемещения
#include &lt;iostream&gt; #include &lt;memory&gt; using namespace std; class A { int x; public: A(int _x) : x(_x){}; ...

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

Не работает конструктор перемещения (C++11)
Прив. Пишу класс подобный string'гу, ну и в процессе изучаю C++. Добрался до оператора и конструктора перемещения. #include...

Конструктор перемещения и оптимизация
Имеем тестовый код: #include &lt;iostream&gt; using namespace std; struct A { A( int v ) { cout &lt;&lt;...

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


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru