Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
#1

Что такое move семантика? - C++

23.11.2014, 19:22. Просмотров 1443. Ответов 17
Метки нет (Все метки)

Что такое move семантика?

Добавлено через 6 минут
Я правильно понимаю, что mov присваивание перемещает правый операнд на место левого? И как его писать?
Пусть есть некий класс, чьи объекты имеют указатель на родителя и указатель на массив потомков.
C++
1
2
3
4
5
6
7
8
class A
{
 A *Parent;
 A *Children;
 size_t Count;
 public:
  A &operator = (A &a);
};
. Как написать реализацию move присваивания для этого класса?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.11.2014, 19:22
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Что такое move семантика? (C++):

move семантика
Сейчас стало появляться нечто вроде такого: class X { public: X (const...

Move семантика (класс полиномов)
Доброго времени суток. Пишу простенький класс полиномов, в котором есть...

Что такое файловый буфер? Что такое режим (модификатор) доступа, при работе с файлами?
Что такое файловый буфер? Что такое режим (модификатор) доступа, при работе с...

Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?
Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?

Что такое хэндлер файла? Что такое файловый указатель?
Что такое хэндлер файла? Что такое файловый указатель?

Что такое заголовочный файл? Что такое файл исходного кода? Рассмотрите назначение каждого из них
Что такое заголовочный файл? Что такое файл исходного кода? Рассмотрите ...

17
Pancir
57 / 44 / 11
Регистрация: 16.09.2014
Сообщений: 124
23.11.2014, 19:28 #2
Вот реально странно, вроде опытный человек на форуме, а задать свой вопрос сперва у гугля не догадывается, там уже все ответы есть.
0
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
23.11.2014, 19:29  [ТС] #3
То есть A &operator = (A &&a);
0
DrOffset
7518 / 4514 / 1097
Регистрация: 30.01.2014
Сообщений: 7,362
23.11.2014, 19:33 #4
Цитата Сообщение от taras atavin Посмотреть сообщение
Как написать реализацию move присваивания для этого класса?
Через swap.
0
Nosey
1350 / 401 / 144
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
23.11.2014, 19:34 #5
Наверное так :
C++
1
2
3
4
5
6
7
8
9
10
11
12
class A
{
 A *Parent;
 A *Children;
 size_t Count;
 public:
  A &operator = (A &&a){
std::swap(Parent,a.Parent);
std::swap(Children,a.Children);
Count = a.Count;
}
};
0
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
23.11.2014, 20:09  [ТС] #6
Цитата Сообщение от Pancir Посмотреть сообщение
а задать свой вопрос сперва у гугля не догадывается, там уже все ответы есть.
Догадался.

Добавлено через 15 минут
C++
1
2
3
4
5
6
7
8
class TDirectory
{
 std::wstring                  Name;
 TDirectory                   *Parent;
 TDirectory                   *Children;
 size_t                        ChildrenCount;
 ...
};
C++
1
2
3
4
5
6
7
8
9
10
        TDirectory                     &
       TDirectory    ::                 operator =                                            (      TDirectory     &&Directory       )
{
 Name         =Directory.Name;
 Parent       =Directory.Parent;
 Children     =Directory.Children
 ChildrenCount=Directory.ChildrenCount;
 Directory.Children     =NULL;
 Directory.ChildrenCount=0;
}
,
на строку
C++
1
*Target=*Source;
пишет
C++
1
error: use of deleted function 'TDirectory& TDirectory::operator=(const TDirectory&)'|
. Я не операционную систему пишу, у меня внутри документа будут каталоги, но с точки зрения операционной системы это будет ровно один файл и каталогов внутри она не увидит.
C++
1
2
 TDirectory *Source;
 TDirectory *Target;
.
0
Nosey
1350 / 401 / 144
Регистрация: 22.10.2014
Сообщений: 863
Завершенные тесты: 2
23.11.2014, 20:13 #7
taras atavin,
Значит *Source не есть rvalue, и мув присваивание не вызывается, а вызывается обычное, которого судя по ошибке нет ))
Либо сами кастуем к rvalue, либо пишем обычное присваивание.
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4385 / 2360 / 655
Регистрация: 18.10.2014
Сообщений: 4,002
23.11.2014, 21:00 #8
Цитата Сообщение от taras atavin Посмотреть сообщение
пишет
error: use of deleted function 'TDirectory& TDirectory::operator=(const TDirectory&)'|
Неформально выражаясь, компилятор будет сам вызывать мув оператор присваивания только тогда, когда компилятор уверен, что объект в правой части - не жилец, т.е. будет уничтожен [почти] сразу после присваивания. В частности, присваивание из временных объектов будет идти по мув оператору

C++
1
2
3
TDirectory *target;
...
*target = TDirectory();
Если же объект в правой части не уничтожается сразу после присваивания, то мув автоматически делаться не будет. Его надо специально заказывать

C++
1
2
3
TDirectory *target, *source;
...
*target = std::move(*source);
1
hoggy
Заблокирован
23.11.2014, 21:46 #9
Цитата Сообщение от taras atavin Посмотреть сообщение
Что такое move семантика?
Самое главное, что нужно понять: вы можете писать методы, которые различают "обычные объекты" (lvalue) и "временные" (rvalue)

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

Покажу на примере:

http://rextester.com/JCQZS64854

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
#include <iostream>
using namespace std;
 
struct sample
{
    int* data;
    
    ~sample()
    {
        if(data)
            cout<<"delete object("<<*data<<")\n";
        else
            cout<<"delete empty object\n";
            
        
        delete data;
    }
    
    sample(const int v)
        : data( new int(v) )
    { cout<<"ctor("<<*data<<")\n"; }
    
    sample():data(nullptr) { cout<<"ctor\n"; }
    sample(const sample&)  { cout<<"copy\n"; }
    sample(sample&&     )  { cout<<"move\n"; }
    
    sample& operator=(const sample& rhs)
    {
        cout<<"copy operator=\n";
        data = new int(*rhs.data);
        return *this;
    }
    
    sample& operator=(sample&& rhs)
    {
        cout<<"move operator=\n";
        
        data = rhs.data;
        rhs.data = nullptr;
        return *this;
    }
};
 
sample foo()
{
    sample s(10);
    return s;
}
 
int main()
{
    std::cout << "Hello, world!\n";
    
    sample s;
    s = foo();
}
sample держит внутри себя указатель на данные в куче.

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

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

Таким образом осуществляются оптимизации создания объектов без необходимости выполнять глубокую копию.

--------------

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

И тогда, вы можете использовать std::move, что бы явно подчеркнуть, что этот объект можно опустошать.
2
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
24.11.2014, 04:25  [ТС] #10
Цитата Сообщение от hoggy Посмотреть сообщение
И тогда, вы можете использовать std::move, что бы явно подчеркнуть, что этот объект можно опустошать.
Как?
0
0x10
2554 / 1734 / 285
Регистрация: 24.11.2012
Сообщений: 4,361
24.11.2014, 04:27 #11
Цитата Сообщение от taras atavin Посмотреть сообщение
Как?
Пост 8, последняя строчка.
0
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
24.11.2014, 04:30  [ТС] #12
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
TDirectory *target, *source; ... *target = std::move(*source);
Здесь нужен конструктор перемещения, или достаточно присваивания?
0
Croessmah
++Ͻ
14163 / 8088 / 1514
Регистрация: 27.09.2012
Сообщений: 19,937
Записей в блоге: 3
Завершенные тесты: 1
24.11.2014, 04:32 #13
Цитата Сообщение от taras atavin Посмотреть сообщение
Что такое move семантика?
вкратце: Семантика перемещения и perfect forwarding(правильная передача)
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
4385 / 2360 / 655
Регистрация: 18.10.2014
Сообщений: 4,002
24.11.2014, 05:20 #14
Цитата Сообщение от taras atavin Посмотреть сообщение
Здесь нужен конструктор перемещения, или достаточно присваивания?
Здесь - именно перемещающий оператор присваивания.
1
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
23.12.2014, 07:31  [ТС] #15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Здесь - именно перемещающий оператор присваивания.
Это понятно. А при его наличии перемещающий конструктор нужен?
0
rikimaru2013
C++ Game Dev
2471 / 1140 / 348
Регистрация: 30.11.2013
Сообщений: 3,709
23.12.2014, 08:14 #16
Цитата Сообщение от taras atavin Посмотреть сообщение
Это понятно. А при его наличии перемещающий конструктор нужен?
Зависит от вашего алгоритма. Один при создании, другой при жизни. Но если уже и работаете с семантикой переноса - то реализуйте оба метода - времени затратите на 30 секунд больше - зато профит.
0
taras atavin
4204 / 1763 / 212
Регистрация: 24.11.2009
Сообщений: 27,565
23.12.2014, 08:18  [ТС] #17
А как его писать? Начиная с прототипа, пожалуйста.
0
rikimaru2013
C++ Game Dev
2471 / 1140 / 348
Регистрация: 30.11.2013
Сообщений: 3,709
23.12.2014, 08:31 #18
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
#include <iostream>
using namespace std;
 
 
class Foo
{
private:
    int* m_ptr = nullptr;
public:
    Foo(int x)
    {
        m_ptr = new int(x);
    }
 
    Foo(Foo&& move)
    {
        m_ptr = move.m_ptr;
        move.m_ptr = nullptr;
    }
    ~Foo()
    {
        delete m_ptr;
    }
 
    void show()
    {
        cout << *m_ptr << endl;
    }
};
 
 
Foo createFoo(int x)
{
    return Foo(x);
}
int main()
{
    Foo a = std::move(createFoo(33));
    a.show();
    
}
1
23.12.2014, 08:31
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.12.2014, 08:31
Привет! Вот еще темы с решениями:

Vector::swap и std::move - что эффективнее?
Пусть имеется пустой вектор A и заполненный некими данными вектор B. Тогда...

Что происходит когда std::move применяется для int?
Мне, вроде бы, понятно как работает std::move() на классах типа string. Но мне...

Объяснить что такое "раздельная компиляция", что такое "интерфейс класса" и "реализация класса" на примере
Есть класс, содержащий объекты и конструктор. Конструктор объявляется в одном...

Что такое перегрузка оператора? Что у меня в коде за ошибка?
Что же я написал?? Что оно не компилится? Что значит error C2275: Superclass:...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

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