Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/21: Рейтинг темы: голосов - 21, средняя оценка - 4.52
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30

Удвоение оператора присваивания

09.08.2021, 15:44. Показов 4325. Ответов 15

Студворк — интернет-сервис помощи студентам
Недавно перешел на VS 2019 с более древних версий языка. И столкнулся с непоняткой.

Прошу прощения, не знаю как нарисовать диаграмму. Представьте себе базовый класс B, у него 2 виртуальных наследника C и D, а класс E множественно наследует C и D.

Все наследники не имеют дополнительных полей данных (членов-не-функций), а отличаются только дополнительными операциями (методами). Как оказалось, в таком случае в новой версии языка нет необходимости писать operator= в наследных классах. Будучи определен в B, operator= успешно срабатывает и с объектами классов-наследников. А если написать, например, C::operator=, то его существование компилятор игнорирует. Вроде бы, нормальное решение. Но...

При вызове E::operator= операция B:operator= выполняется дважды подряд! С неприятными побочными эффектами. Если исключить D из иерархии, тогда все нормально. Если дополнительно подключить зависимость B <- E виртуально напрямую, то B::operator= исполняется трижды.

Помогите исправить, пожалуйста.

Добавлено через 2 часа 52 минуты
А вот и демонстрашка: https://disk.yandex.ru/d/JveYl2vJSGtCcw
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.08.2021, 15:44
Ответы с готовыми решениями:

Избыточное копирование объекта при реализации оператора умножения и оператора присваивания
Есть класс работы с матрицами. Есть операция умножения матриц, описанная как оператор класса. В данном коротком примере я просто моделирую...

Неправильная работа оператора присваивания после работы оператора суммирования
Доброго времени суток. У меня есть класс вектор class TVector {//ewde public: TVector(); //Vector(Vector &amp;v); ...

Перегрузка оператора присваивания
мне надо было реализовать конструкторы, деструктор, оператор присваивания, функции ввода / вывода объектов; кто сможет дописать...

15
фрилансер
 Аватар для Алексей1153
6472 / 5687 / 1131
Регистрация: 11.10.2019
Сообщений: 15,167
09.08.2021, 16:35
VTs1954, привет. Сделай максимально упрощённый пример с проявляющейся "ошибкой"
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 16:38  [ТС]
Уже! https://disk.yandex.ru/d/JveYl2vJSGtCcw

op=m -- след оператора присваивания перемещающего
MA -- след от кода, вызываемого из operator= и реализующего операцию.
0
фрилансер
 Аватар для Алексей1153
6472 / 5687 / 1131
Регистрация: 11.10.2019
Сообщений: 15,167
09.08.2021, 16:42
VTs1954, там лапша-лапша на несколько экранов.

Вот заготовка, сделай форк и добавь пару заветных строк, чтобы продемонстрировать ошибку

https://onlinegdb.com/Nj8ohrc1x
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 17:08  [ТС]
Так лучше? Ссылка прежняя.
0
фрилансер
 Аватар для Алексей1153
6472 / 5687 / 1131
Регистрация: 11.10.2019
Сообщений: 15,167
09.08.2021, 17:58
Цитата Сообщение от VTs1954 Посмотреть сообщение
Так лучше
не намного

вот, я слегка почистил пример.
https://onlinegdb.com/vNdGFLjYU

действительно, вызывается два перемещения, но почему - я не понял. Также компилятор выдаёт предупреждение, которое я не понимаю, как исправить

Ждём более опытных товарищей

Добавлено через 1 минуту
VTs1954, а double * coord{}; лучше замени на std::vector
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 18:07  [ТС]
Вот еще проще:
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
#include <iostream>
 
class B
  {
protected:  
   int n;
 
public: 
// Constructors
    B() : n(0) {};
    B(int N) : n(N) {};
 
// Destructor
   ~B(){n = 0;} 
 
 
   B & operator=(const B & U)  // copy assign
   {
printf("copy = B -> B\n");
    n = U.n;
    return *this;
   }
   B & operator=(B && U)       // move assign
   {
printf("move = _B -> _B\n");
    n = U.n;
    U.n = 0;
    return *this;
  }
 
//Debug function
   void Display() const
     {
      std::cout << n;
     }
  }; // end of  class B
  
//////////////////  D ///////////
class C: public virtual B
  {
  }; // end of class D
 
 
//////////////////  D ///////////
class D: public virtual B
  {
  }; // end of class D
 
//////////////////  E ///////////
class E: public C, public D
  {
public:
// Constructors
   E(): B(){};
   E(int N): B(N){};
  }; // end of class E
  
  
////////////  main  ///////////  
int main()
  {
   E y(3);
   E z;
   z = std::move(y);
   z.Display();
   return 0;
  }
Если убрать move, будет двойное копирование.
0
09.08.2021, 18:13

Не по теме:

VTs1954, зачем эти мусорные комментарии :wall: Они не несут никакой информации, только глаза разбегаются

и так понятно, что это конструктор, это деструктор, это main :D

0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 18:37  [ТС]
Не подозревал, что это портит ваши глаза. Мне это важно -- привычка, понимаешь...

Добавлено через 21 минуту
Гипотеза: количество повторов конструктора равно количеству путей от E к B. "но почему - я не понял"
0
фрилансер
 Аватар для Алексей1153
6472 / 5687 / 1131
Регистрация: 11.10.2019
Сообщений: 15,167
09.08.2021, 18:48
VTs1954, конструкторы на строке z = std::move(y); не вызываются, только оператор перемещения
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 18:51  [ТС]
Ой, оговорился! Конечно, надо было сказать "оператора присваивания".
0
фрилансер
 Аватар для Алексей1153
6472 / 5687 / 1131
Регистрация: 11.10.2019
Сообщений: 15,167
09.08.2021, 18:52
VTs1954, перемещения
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
09.08.2021, 18:54  [ТС]
Это уже вопрос терминологии. Я различаю копирующий и перемещающий операторы присваивания. Они оба демонстрируют обнаруженную особенность.
0
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
11.08.2021, 09:58  [ТС]
Уп-ф?

Вопрос остается открытым. Вот еще более короткая версия теста:
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>
 
class B
  {
protected:  
   int n;
public: 
    B() : n(0) {};
    B(int N) : n(N) {};
 
   ~B(){n = 0;} 
 
   B & operator=(const B & U)  // copy assign
   {
printf("copy = \n");
    n = U.n;
    return *this;
   }
   B & operator=(B && U)       // move assign
   {
printf("move = \n");
    n = U.n;
    U.n = 0;
    return *this;
   }
 
void Display() const
     {
      std::cout << n << "\n";
     }
  }; 
 
class C: public virtual B
  {
  };
 
class D: public virtual B
  {
  }; 
 
class E: public C, public D
  {
public:
   E(): B(){};
   E(int N): B(N){};
  }; 
  
int main()
  {
   E y(3);
   E z;
   z = y;
   z = std::move(y);
   z.Display();
   return 0;
  }
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13200 / 6835 / 1822
Регистрация: 18.10.2014
Сообщений: 17,293
12.08.2021, 19:38
Цитата Сообщение от VTs1954 Посмотреть сообщение
Вопрос остается открытым.
Таковы реалии языка С++. Уникальность вызова специальной функции для виртуальных базовых классов гарантируется только для конструкторов и деструкторов. Для неявно определенного оператора присваивания такой гарантии нет

http://eel.is/c++draft/class.copy.assign#12
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy/move assignment operator.
То есть вам нужно быть готовым к тому, что неявно определенный оператор присваивания класса-наследника вызовет оператор присваивания виртуальной базы более одного раза. Например, в присутствии виртуального наследования не полагайтесь на неявно определенные операторы присваивания в классах-наследниках вообще. Пишите их сами, руками.
1
0 / 0 / 0
Регистрация: 05.07.2021
Сообщений: 30
12.08.2021, 20:32  [ТС]
Компилятор Open Watcom таких плюх не допускает.

Unspecified... Грустно!

Буду еще раз пробовать. Спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.08.2021, 20:32
Помогаю со студенческими работами здесь

Перегрузка оператора присваивания
Здравствуйте! Помогите, пожалуйста разобраться с перегрузкой оператора присваивания. Нужно написать класс матрица, в котором есть...

Перегрузка оператора присваивания
Доброго времени суток! Возник вопрос по поводу перегрузки оператора присваивания. Пример перегрузки по канону: class Integer { ...

Перегрузка оператора присваивания
Вот есть такой класс template&lt;typename TT&gt; class Matrix { public: ...

Перегрузка оператора присваивания
Задание простое: по заданному классу составить простую программу с использованием динамической памяти. class Cow { char name; ...

Перегрузка оператора присваивания
Всем привет! По заданию программа должна содержать перегруженную операцию «=», использование которой скопирует содержимое одной строки...


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

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача №1: при указании работ (справочник РаботыПоРемонтуСпецтехники),. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru