C ++ Назначение странное поведение

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

#include <iostream>
#include <new>

using namespace std;

template<class CRTP>
class object_t {
public:
object_t<CRTP> &operator=(const object_t<CRTP> &a) {
((CRTP*)this)->~CRTP();
new ((CRTP*)this) CRTP(*(const CRTP*)&a);
cout << "Value in assignment: " << ((CRTP*)this)->n << endl;
return *this;
}
};

class darr_t : public object_t<darr_t> {
public:

int n;

darr_t(const darr_t &a) : n(a.n + 1) {
cout << "Value in constructor: " << n << endl;
}

darr_t(int pn) : n(pn) {}
};

int main() {

darr_t tmp(42);
darr_t tmp2(55);
tmp = tmp2;

cout << "Value in main: " << tmp.n << endl;

return 0;
}

Выход:

Значение в конструкторе: 56
Значение в назначении: 56
Значение в основном: 55

Ожидаемый результат:

Значение в конструкторе: 56
Значение в назначении: 56
Значение в основном: 56

Редактировать:
Спасибо @ Cheersandhth.-Alf и @ Mr_Hic-up ответы!
Проблема в том, что по умолчанию darr_t :: operator = сначала вызывает назначение базового типа, но после этого вызывает назначение (переопределение) для членов объекта darr_t!

2

Решение

Вы наблюдаете за поведением, потому что:

  1. Компилятор определяет оператор неявного копирования для darr_t,
  2. Неявное назначение копирования вызывает оператор назначения копирования базового класса перед выполнением назначения копии переменных-членов.

Вот соответствующая документация от http://en.cppreference.com/w/cpp/language/as_operator:

Неявно объявленный оператор присваивания копии

Если для типа класса не заданы пользовательские операторы назначения копирования (struct, class, или же union), компилятор всегда объявляет его как встроенный открытый член класса. Этот неявно объявленный оператор присваивания копии имеет вид T& T::operator=(const T&) если все следующее верно:

каждая прямая база B из T имеет оператор присваивания копии, параметры которого B или же const B& или же const volatile B&

каждый элемент не статических данных M из T типа класса или массива типа класса имеет оператор присваивания копии, параметры которого M или же const M& или же const volatile M&

В противном случае неявно объявленный оператор присваивания копии объявляется как T& T::operator=(T&), (Обратите внимание, что из-за этих правил неявно объявленный оператор присваивания копии не может связываться с переменным аргументом lvalue)

2

Другие решения

    new ((CRTP*)this) CRTP(*(const CRTP*)&a);

Та магия указателя, которую вы пытаетесь использовать, не делает того, чего вы ожидаете. Добавляем несколько строк, чтобы распечатать адреса объекта перед печатью переменной yields (на моем компьютере):

Address in constructor: 0x7fff56264610
Value in constructor: 56
Address in assignment: 0x7fff56264610
Value in assignment: 56
Address in main: 0x7fff56264618
Value in main: 55
0

По вопросам рекламы ammmcru@yandex.ru