Ваш код вызывает неопределенное поведение.
Не просто "неопределено, если A используется в качестве базового класса и того, и того, или другого".На самом деле не определено, всегда.return *this
уже является UB, потому что this
не гарантирует обращения к новому объекту.
В частности, рассмотрим 3.8 / 7:
Если по истечении времени жизниобъект завершился, и до того, как хранилище, которое занимал объект, используется повторно или освобождено, в месте хранения, которое занимал исходный объект, создается новый объект, указатель, который указывал на исходный объект, ссылка, ссылающаяся на исходный объект, илиимя исходного объекта будет автоматически ссылаться на новый объект и после запуска времени жизни нового объекта может использоваться для управления новым объектом, если:
...
- тип исходного объекта не является константно-квалифицированным и, если тип класса, не содержит какого-либо нестатического члена данных, тип которого является константно-квалифицированным или ссылочным типом,
Теперь, «после того, как время жизни объекта закончилось и до того, как хранилище, которое занимал объект, используется повторно или освобождено, новый объект создается в хранилищевозраст, который занимал исходный объект "- это именно то, что вы делаете.
Ваш объект относится к типу класса, и он содержит содержит нестатический элемент данных, тип которого является константно-квалифицированным,Поэтому после запуска вашего оператора присваивания указатели, ссылки и имена, ссылающиеся на старый объект, гарантированно не ссылаются на новый объект и могут использоваться для манипулирования им.
Какконкретный пример того, что может пойти не так, рассмотрим:
A x(1);
B y(2);
std::cout << x.c << "\n";
x = y;
std::cout << x.c << "\n";
Ожидайте этот вывод?
1
2
Неправильно!Вероятно, вы могли бы получить этот вывод, но причина, по которой члены const являются исключением из правила, изложенного в 3.8 / 7, заключается в том, что компилятор может обрабатывать x.c
как объект const, который, как он утверждает, является.Другими словами, компилятору разрешено обрабатывать этот код так, как если бы он был:
A x(1);
B y(2);
int tmp = x.c
std::cout << tmp << "\n";
x = y;
std::cout << tmp << "\n";
Поскольку (неофициально) объекты const не изменяют свои значения .Потенциальное значение этой гарантии при оптимизации кода с использованием константных объектов должно быть очевидным.Чтобы существовал какой-либо способ изменить x.c
без , вызывающего UB, эта гарантия должна быть удалена.Так что, пока стандартные авторы выполнили свою работу без ошибок, нет способа делать то, что вы хотите.
[*] На самом деле у меня есть сомнения относительно использования this
в качестве аргумента для размещенияnew - возможно, вам следовало сначала скопировать его в void*
и использовать его.Но меня не беспокоит, является ли это UB, поскольку это не спасет функцию в целом.