С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
0 / 0 / 0
Регистрация: 06.06.2017
Сообщений: 61
1

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

24.08.2022, 12:23. Показов 1854. Ответов 33
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте! Изучил тему конструктор и оператор перемещения, и написал следующий код:
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
#include <iostream>
#include <stdlib.h>
using namespace std;
class Transfer {
private:
    double* d;
    int count;
    void Free() {
        if (count != 0)
            delete[] d;
        count = 0;
    }
public:
    ~Transfer() {
        Free();
    }
    Transfer(double* new_d, int c)
    {
        Free();
        d = new double[c];
        for (int i = 0; i < c; i++)
            d[i] = new_d[i];
        count = c;
    }
    Transfer() : Transfer(nullptr, 0) {}
    Transfer(Transfer&& t) noexcept {
        this->count = t.count;
        this->d = t.d;
        t.count = 0;
        cout << "Конец работы конструктора переноса\n";
    }
    Transfer& operator=(Transfer&& t) noexcept{
        Free();
        if (this != &t)
        {
            this->count = t.count;
            this->d = t.d;
            t.count = 0;
        }
        cout << "Конец работы оператора переноса\n";
        return *this;
    }
    void Print() {
        cout << "{";
        for (int i = 0; i < count - 1; i++)
            cout << d[i] << ", ";
        if (count >= 1)
            cout << d[count - 1];
        cout << "}\n";
    };
}; 
Transfer GetD(int k) {
    double* d = new double[k];
    for (double* q = d; q != d + k; q++)
        *q = rand();
    Transfer t(d, k);
    cout << "Конец создания массива\n";
    return t;
};
int main()
{
    setlocale(LC_ALL, "Rus");
    srand(time(0));
    double* d = new double[] {12, 8, 5};
    Transfer t(d, 3);
    t.Print();
    t = GetD(100);
 
}
Не могу понять, почему у меня вызывается и конструктор переноса и оператор.
0
IT_Exp
Эксперт
8794 / 1073 / 104
Регистрация: 17.06.2006
Сообщений: 12,602
Блог
24.08.2022, 12:23
Ответы с готовыми решениями:

Конструктор перемещения и оператор присвоения для двусвязного списка
Добрый день. Помогите разобраться в вопросом: пишу реализацию двусвязного списка, хотел бы...

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

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

конструктор перемещения
Добрый день. Пишу конструктор перемещения для своего класса. В классе содержится переменная типа...

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

33
3718 / 2647 / 761
Регистрация: 29.06.2020
Сообщений: 9,800
24.08.2022, 12:41 2
SergMT, у вас вообще UB
Free(); в конструкторе

Добавлено через 1 минуту
После исправления UB
Код
{12, 8, 5}
Конец создания массива
Конец работы оператора переноса
0
4264 / 3323 / 925
Регистрация: 25.03.2012
Сообщений: 12,520
Записей в блоге: 1
24.08.2022, 14:42 3
SergMT, дело даже не в том, что это приводит к ошибке. Непонятно, почему конструктор копий так похож на оператор равно?
Очевидно же, что в том контексте, что вызывается конструктор нет никаких данных в объекте, которые нужно освободить. Мы на то и конструктор, чтобы первым делом попадать в к полям нового объекта, пока ещё не заполненного ничем.
0
3718 / 2647 / 761
Регистрация: 29.06.2020
Сообщений: 9,800
24.08.2022, 15:03 4
Kuzia domovenok, да там куда не стань ногу сломаешь,
обычные конструкторы сами себя вешают, дальше смотреть не на что.
0
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
24.08.2022, 16:39 5
SergMT, сначала изучите копирующие (и пр.) конструктора и оператор присваивания. Потом перемещающие. При перемещении вы должны не только перевесить ресурсы из объекта-трупа. Нужно убить их на умершем объекте. Тут достаточно написать :t.d=nullptr (после присвоения в указатель принимающего объекта, конечно). Теперь delete в деструкторе объекта источника - t, безопасен. Однако, обычные "простые" конструкторы и операторы не так просты, чтобы не потратить на них время. Изучите. Тогда разноплановые ошибки не будут хороводить и фестивалить, мешая чтению основной идеи - перемещения. Термин, кстати, не лучший. По сути, ресурсы (низкоуровневые сущности) не перемещаются, в памяти (низкоуровневый базовый ресурс). Объект захватывает их оставляя жертву пустой личной. По смыслу это семантика захвата. Но в программировании куда ни плюнь, - уже наплёвано.
0
SmallEvil
24.08.2022, 16:57
  #6

Не по теме:

Цитата Сообщение от IGPIGP Посмотреть сообщение
Термин, кстати, не лучший.
i like to moved moved
В танце тоже никто никуда особо не перемещается, но все же :)
То есть англ. move это не только перемещать, но и двигать, шевелить.
Мы же все таки при обмене ресурсами пошевелили указателями ?
А вообще, забавное замечание.

0
Вездепух
Эксперт CЭксперт С++
12798 / 6674 / 1796
Регистрация: 18.10.2014
Сообщений: 16,894
24.08.2022, 17:26 7
Цитата Сообщение от SergMT Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
    Transfer(double* new_d, int c)
    {
        Free();
        d = new double[c];
        for (int i = 0; i < c; i++)
            d[i] = new_d[i];
        count = c;
    }
Почему конструктор у вас начинается с вызова Free()? Объект еще не сконструирован/не инициализирован. У него непредсказуемое состояние. С чем будет работать Free()? Какие значения полей она будет проверять?

Цитата Сообщение от SergMT Посмотреть сообщение
Не могу понять, почему у меня вызывается и конструктор переноса и оператор.
Ваша программа падает из-за причин приведенных выше, а не "вызывается и конструктор переноса и оператор".

Но, после исправления ошибки, вызываться и конструктор переноса и переносящий оператор присваивания может потому, что по-видимому ваш компилятор не выполнил copy elision, т.е. работает в режиме негарантированного copy elision (какой стандарт у вас включен?). Конструктор переноса вызывается при возврате значения функции GetD, а оператор присваивания вы сами вызываете в своей программе.
0
zayats80888
24.08.2022, 18:52
  #8

Не по теме:

Цитата Сообщение от SmallEvil Посмотреть сообщение
i like to moved
i like to move it

0
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
24.08.2022, 20:48 9
Цитата Сообщение от SmallEvil Посмотреть сообщение
Мы же все таки при обмене ресурсами пошевелили указателями ?
И пальцами, - набирая код конструктора. Ресурсы не двигаются при передаче владения. Они меняют хозяина по воле принимающего хозяина - грабителя. Это можно назвать и перемещением. Полит-корректно. Дело в том, что перемещение - антоним состояния покоя. Простые конструкторы и операторы (копирующие операции) ни каким покоем похвастать не могут. Они копируют, дублируют или вообще говоря размножают. Таким образом, копирование и захват - противоположны семантически, а перемещение это не удачно. А про указатели (шевелимые) , достаточно вспомнить - удаление указателей операцией по имени delete. А потом объясняем новичкам, что указатели то не удаляются, а происходит нечто иное. Терминология) Я не вижу, тут офтопа SmallEvil )
0
Вездепух
Эксперт CЭксперт С++
12798 / 6674 / 1796
Регистрация: 18.10.2014
Сообщений: 16,894
24.08.2022, 21:45 10
Цитата Сообщение от IGPIGP Посмотреть сообщение
сначала изучите копирующие (и пр.) конструктора и оператор присваивания. Потом перемещающие. При перемещении вы должны не только перевесить ресурсы из объекта-трупа. Нужно убить их на умершем объекте.
Поток бессмыслицы. Ни в коем случае перемещение не "умерщвляет" объект и ни к коем случае перемещенный объект не является никаким "трупом".

Постарайтесь запомнить: перемещение - рядовая модифицирующая операция, потенциально (но не обязательно) изменяющая состояние исходного объекта. Ее статус - точно такой же, как и у любой другой потенциально модифицирующей операции. На примере std::vector, статус перемещения таков же, как и у operator [] или метода resize. Сколько уж усилие положено людьми на то, чтобы вдолбить в бошки этот простой факт, но все как об стенку горох...

Ни о каком "умерщвлении" или "трупе" не может быть и речи. Объект, подвергнувшийся перемещению - это обыкновенный объект, который возможно модифицировали. Он ни в коем случае не является "мертвым". А уж какой модификации он подвергся (если подвергся) - читайте документацию, проверяйте вызовом методов и т.д.

Цитата Сообщение от IGPIGP Посмотреть сообщение
Тут достаточно написать :t.d=nullptr (после присвоения в указатель принимающего объекта, конечно). Теперь delete в деструкторе объекта источника - t, безопасен.
Ничего этого делать не нужно. ТС предпринял все необходимые меры, чтобы написать безопасный деструктор. Никакой необходимости делать t.d=nullptr в перемещающих методах нет. Достаточно t.count = 0.

Цитата Сообщение от IGPIGP Посмотреть сообщение
Простые конструкторы и операторы (копирующие операции) ни каким покоем похвастать не могут. Они копируют, дублируют или вообще говоря размножают. Таким образом, копирование и захват - противоположны семантически, а перемещение это не удачно.
Опять поток бессмыслицы.

Концепция перемещения в С++ - расширение концепции копирования. Любое классическое копирование автоматически является перемещением (является частным примером перемещения).

Поэтому ни о каком "противоположны семантически" речи быть не может. Перемещение и копирование - неразлучные родные братья.
2
3718 / 2647 / 761
Регистрация: 29.06.2020
Сообщений: 9,800
24.08.2022, 22:15 11
Цитата Сообщение от IGPIGP Посмотреть сообщение
копирование и захват
захват , по моему, это когда один отобрал у другого.
Нельзя обмен назвать захватом.
То что я ему фальшивые доллары всунул (nullptr или другую хрень) в абстрактном мире программирования никого не волнует.
То есть , даже конструктор перемещения, выглядит как обмен.
C++
1
2
this->my_res = nullptr;
swap(this->my_res, other.my_res);
Сделка завершена. Все довольны
0
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
24.08.2022, 22:43 12
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Поэтому ни о каком "противоположны семантически" речи быть не может.
TheCalligrapher, с вами мне лично нет смысла обсуждать то чего может или не может быть.
SergMT, я не увидел того что вы придумали с флажком count. на мой взгляд это плохая затея. Операция освобождения владения делается в несколько шагов. Переменная count опасна. Представьте что клиентский код передаст ноль в с аргументом int c сюда:
C++
1
2
3
4
5
6
7
8
Transfer(double* new_d, int c)
    {
        Free();
        d = new double[c];
        for (int i = 0; i < c; i++)
            d[i] = new_d[i];
        count = c;
    }
мне не приходилось такого делать, но я помню, что плюсы позволяют выделить new int[0];. При этом указатель не устанавливается в ноль. Самое интересное это то, что память под нулевой массив таки выделяется. Плюсы гарантируют уникальный адрес для объектов нулевой длины. А в вашем случае, delete в конструкторе вызван уже не будет. Это плохо. Но это не все недостатки такого способа передачи владения. А этика не улучшается. Объект грабитель "инвалидизирует/устраняет" объект жертву и в этом случае. Но при работе с указателем напрямую, можно изменять значение неблокирующей операцией, так как есть std::atomic<std::uintptr_t>.
SergMT, сейчас тут польется новый поток "бред/чушь" и пр. Это нормально)

Добавлено через 1 минуту
Цитата Сообщение от SmallEvil Посмотреть сообщение
То есть , даже конструктор перемещения, выглядит как обмен.
У нас разные глаза. Но можно сойтись, хотя бы на том, что он не выглядит как перемещение. Конструктор это инициализирующий метод. Он не может что-то отдать. У него нет объекта и возможности, соответственно. А позаниматься хирургией на печени партнёра по обмену, это бандитизм.
0
Вездепух
Эксперт CЭксперт С++
12798 / 6674 / 1796
Регистрация: 18.10.2014
Сообщений: 16,894
24.08.2022, 22:45 13
Цитата Сообщение от IGPIGP Посмотреть сообщение
с вами мне лично нет смысла обсуждать то чего может или не может быть.
Никакого обсуждения тут нет. Я просто исправил написанную чепуху - в первую очередь для окружающих, не для вас.
0
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
24.08.2022, 22:47 14
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Я просто исправил написанную чепуху
Тщеславие и упрямство. Валяйте.
0
TheCalligrapher
24.08.2022, 23:06
  #15

Не по теме:

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

0
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
24.08.2022, 23:20 16
Цитата Сообщение от IGPIGP Посмотреть сообщение
А в вашем случае, delete в конструкторе вызван уже не будет.
В деструкторе. То есть, код может породить утечку памяти.
0
0 / 0 / 0
Регистрация: 06.06.2017
Сообщений: 61
25.08.2022, 13:25  [ТС] 17
Насчёт Free() в конструкторе - исправил, но проблему, вопреки тому что написал SmallEvil это не решило. Насчёт того, что всё написанное - бред от начала и до конца, отошлю сюда. То что бывает массив длиной 0 моя программа не обрабатывает. В остальном (вопрос в первую очередь к TheCalligrapher) всё-таки я не понял: это нормально, что вызываются и конструктор и оператор? Или должно быть как-то ещё?
Кстати, за этим шквалом критики, так и не прозвучало, что именно нужно поправить, если всё-таки код не валидный (вопрос ко всем)?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
25.08.2022, 13:50 18
Цитата Сообщение от SergMT Посмотреть сообщение
что именно нужно поправить
Если по-минимуму, то примерно так:
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
#include <iostream>
#include <cstdlib> // !
using namespace std;
 
class Transfer {
private:
    double* d;
    int count;
    void Free() {
        if (count != 0) {
            delete[] d;
            count = 0;
        }
    }
public:
    ~Transfer() {
        Free();
    }
    Transfer(const double* new_d, int c) // !
        : d(new double[c]), count(c)
    {
        for (int i = 0; i < c; i++)
            d[i] = new_d[i];
    }
    Transfer() 
        : Transfer(nullptr, 0) 
    { }
    
    Transfer(Transfer&& t) noexcept // !
        : d(t.d), count(t.count)
    {
        t.count = 0;
        cout << "Конец работы конструктора переноса\n";
    }
    Transfer& operator=(Transfer&& t) noexcept 
    {
        // !
        if (this != &t) {
            swap(t.d, d);
            swap(t.count, count);
        }
        cout << "Конец работы оператора переноса\n";
        return *this;
    }
 
    void Print() {
        cout << "{";
        for (int i = 0; i < count - 1; i++)
            cout << d[i] << ", ";
        if (count >= 1)
            cout << d[count - 1];
        cout << "}\n";
    }
}; 
Transfer GetD(int k) {
    double* d = new double[k];
    for (double* q = d; q != d + k; q++)
        *q = rand();
    Transfer t(d, k);
    delete[] d; // !
    cout << "Конец создания массива\n";
    return t;
};
int main()
{
    setlocale(LC_ALL, "Rus");
    srand(time(0));
    int c = 3;
    double* d = new double[c] {12, 8, 5};
    Transfer t(d, c);
    delete[] d; // !
    t.Print();
    t = GetD(100);
}
1
Комп_Оратор)
Эксперт по математике/физике
9005 / 4704 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.08.2022, 17:39 19
Цитата Сообщение от SergMT Посмотреть сообщение
вопрос ко всем
В последнем примере та же утечка. Уберите функцию Free. Не используйте count как флаг для диспетчеризации удаления освобождения массива. Используйте nullptr, - на нём delete безопасен. Совет: Уберите из класса неспецифический для контейнера метод. Написать как это сделать?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
25.08.2022, 17:54 20
SergMT, оратор выше прав. Функцию Free нужно как минимум исправить так:
C++
1
2
3
4
5
    
void Free() {
    delete[] d;
    count = 0;
}
Как максимум можно от неё избавиться совсем.

Конструктор перемещения соответственно исправить так:
C++
1
2
3
4
5
6
7
   Transfer(Transfer&& t) noexcept // !
        : d(t.d), count(t.count)
    {
        t.count = 0;
        t.d = nullptr;
        cout << "Конец работы конструктора переноса\n";
    }
1
25.08.2022, 17:54
BasicMan
Эксперт
19315 / 2622 / 84
Регистрация: 17.02.2009
Сообщений: 10,364
Блог
25.08.2022, 17:54
Помогаю со студенческими работами здесь

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

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

Для шаблонного класса перегрузить оператор присваивания, copy-конструктор, объекты cin и cout, оператор *
Помогите в следующем: Для класса шаблона следует перегрузить оператор присваивания, конструктор...

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Блоги программистов
Обновление сайта www.historian.b­y
Reglage 05.01.2025
Обещал подвести итоги 2024 года для сайта. Однако начну с того, что изменилось за неделю. Добавил краткий урок по последовательности действий при анализе вредоносных файлов и значительно улучшил урок. . .
Как использовать GraphQL в C# с HotChocolate
Programming 05.01.2025
GraphQL — это современный подход к разработке API, который позволяет клиентам запрашивать только те данные, которые им необходимы. Это делает взаимодействие с API более гибким и эффективным по. . .
Модель полного двоичного суматора с помощью логических операций (python)
AlexSky-coder 04.01.2025
def binSum(x:list, y:list): s=^y] p=x and y for i in range(1,len(x)): s. append((x^y)^p) p=(x and y)or(p and (x or y)) return s x=list() y=list()
Это мы не проходили, это нам не задавали...(аси­­хронный счётчик с управляющим сигналом задержки).
Hrethgir 04.01.2025
Асинхронный счётчик на сумматорах (шестиразрядный по числу диодов на плате, но наверное разрядов будет больше - восемь или шестнадцать, а диоды на старшие), так как триггеры прошли тестирование и. . .
Руководство по созданию бота для Телеграм на Python
IT_Exp 04.01.2025
Боты для Телеграм представляют собой автоматизированные программы, которые выполняют различные задачи, взаимодействуя с пользователями через интерфейс мессенджера. В данной статье мы рассмотрим,. . .
Применение компонентов PrimeVue в Vue.js 3 на TypeScript
BasicMan 04.01.2025
Введение в PrimeVue и настройка окружения PrimeVue представляет собой мощную библиотеку компонентов пользовательского интерфейса для Vue. js 3, которая предоставляет разработчикам богатый набор. . .
Как стать Senior developer
cpp_developer 04.01.2025
В современной индустрии разработки программного обеспечения позиция Senior Developer представляет собой не просто следующую ступень карьерной лестницы, а качественно новый уровень профессионального. . .
Что известно о дате выхода Windows 12 и чего от нее ждать
IT_Exp 04.01.2025
В мире технологий постоянно происходят изменения, и операционные системы не являются исключением. Windows 11, выпущенная в октябре 2021 года, принесла множество инноваций и улучшений, но. . .
Что новенького в .NET Core 9
Programming 04.01.2025
Обзор ключевых изменений в . NET Core 9 Платформа . NET Core продолжает активно развиваться, и версия 9 представляет собой значительный шаг вперед в эволюции этой технологии. Новый релиз. . .
Инструкция по установке python3.13.1 в Debian 12
AlexSky-coder 03.01.2025
sudo apt update sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev wget. . .
Затестил триггеры. архив проекта прилагаю с GOA файлами в настройках архиватора проектов.
Hrethgir 03.01.2025
В этот раз нет закольцованности, потому что от неё только глюки, как я понял, логика не вырезанная. Триггеры очень быстрые если верить измерениям с помощью анализатора от Gowin. Есть ещё регистры,. . .
Python в помощь DevOps
IT_Exp 03.01.2025
Причины использования Python в работе DevOps Python стал неотъемлемой частью мира DevOps, и это не случайно. Этот язык программирования обладает множеством преимуществ, которые делают его. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru