Это продолжение моего предыдущего вопроса, где я, кажется, сделал проблему более сложной, чем предполагал изначально. (См. Обсуждения в вопросе и ответы на комментарии там.) Этот вопрос представляет собой небольшую модификацию исходного вопроса, устраняющую проблему особых правил во время строительства / разрушения ограждающего объекта.
Разрешено ли повторно использовать хранилище нестатического элемента данных в течение всего времени существования включающего его объекта, и если да, то при каких условиях?
Рассмотрим программу
#include<new>
#include<type_traits>
using T = /*some type*/;
using U = /*some type*/;
static_assert(std::is_object_v<T>);
static_assert(std::is_object_v<U>);
static_assert(sizeof(U) <= sizeof(T));
static_assert(alignof(U) <= alignof(T));
struct A {
T t /*initializer*/;
U* u;
void construct() {
t.~T();
u = ::new(static_cast<void*>(&t)) U /*initializer*/;
}
void destruct() {
u->~U();
::new(static_cast<void*>(&t)) T /*initializer*/;
}
A() = default;
A(const A&) = delete;
A(A&&) = delete;
A& operator=(const A&) = delete;
A& operator=(A&&) = delete;
};
int main() {
auto a = new A;
a->construct();
*(a->u) = /*some assignment*/;
a->destruct(); /*optional*/
delete a; /*optional*/
A b; /*alternative*/
b.construct(); /*alternative*/
*(b.u) = /*some assignment*/; /*alternative*/
b.destruct(); /*alternative*/
}
Помимо static_assert
s предполагаем, что инициализаторы, деструкторы и присваивания T
и U
не выбрасываются.
Какие условия должны дополнительно удовлетворять типы объектов T
и U
, чтобы программа имела определенное поведение, если таковое имеется?
Зависит ли это от фактического вызова деструктора A
(например, присутствуют ли строки /*optional*/
или /*alternative*/
)?
Зависит ли это от продолжительности хранения A
, например используются ли вместо этого /*alternative*/
строк в main
?
Обратите внимание, что программа не использует член t
после нового размещения, за исключением деструктора и функции destruct
. Конечно, использование его, когда его хранилище занято другим типом, не допускается.
Также обратите внимание, что программа создает объект исходного типа в t
до того, как его деструктор вызывается во всех путях выполнения, поскольку я запретил T
и U
генерировать исключения.
Также обратите внимание, что я никого не призываю писать подобный код. Я намерен лучше понимать детали языка. В частности, я не нашел ничего, запрещающего такие новости о размещении, пока, по крайней мере, не вызывается деструктор.