Имеет ли объект, созданный с размещением new, динамическую продолжительность хранения?

(5.3.4)

новое выражение:

  • :: opt_ new new -place_ opt new-type-id new-initializeropt

  • :: opt_ new new -place_ opt (type-id) new-initializeropt

Объекты, созданные новым выражением, имеют динамическую продолжительность хранения (3.7.4). [Примечание: время жизни такого объекта не обязательно ограничено областью, в которой он создан. - конец примечания]

Я думаю, что у следующего есть 1 основной объект (local_object) с автоматической продолжительностью хранения и 3 фиктивных класса с динамической продолжительностью хранения.

struct dummy
{
    int a;
};

char local_object[256];
dummy * a = new(&local_object) dummy;
dummy * b = new(&local_object +100) dummy;
dummy * c = new(&local_object +200) dummy;

Пользователь @MM утверждает, что существует только один объект (local_object), а остальные являются просто указателями. Это правильно?

(3.7)

Динамическая продолжительность хранения связана с объектами, созданными с помощью оператора new

1 ответ

Решение

Мне кажется, что стандарт (как указано в ОП) можно интерпретировать только при чтении, то есть оператор new создает объекты с динамическим сроком хранения, и это верно, даже если базовая память была получена для объекта автоматического продолжительность.

Этот точный сценарий предусмотрен стандартом в параграфе 8 §3.8 [basic.life] со ссылкой на следующий пример неопределенного поведения:

class T { };
struct B {
    ~B();
};
void h() {
    B b;
    new (&b) T;
}

Абзац гласит:

Если программа заканчивает время жизни объекта типа T со статическим (3.7.1), потоком (3.7.2) или автоматическим (3.7.3) сроком хранения и если T имеет нетривиальный деструктор, программа должна обеспечить что объект исходного типа занимает то же место хранения, когда происходит неявный вызов деструктора; в противном случае поведение программы не определено.

В примере программа "закончила время жизни" объекта b путем повторного использования хранилища, как это предусмотрено в пункте 4 того же раздела: (выделение добавлено).

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

В примере кода bДеструктор не был вызван, но это приемлемо, потому что параграф 4 явно позволяет не вызывать нетривиальный деструктор:

Для объекта типа класса с нетривиальным деструктором программе не требуется явно вызывать деструктор до повторного использования или освобождения хранилища, которое занимает объект;

до тех пор, пока программа готова жить с последствиями того, что деструктор не будет вызван.

Но вернемся к пункту 8, bвремя жизни закончилось, и хранилище было повторно использовано для создания объекта типа T, Этот объект имеет динамическую продолжительность хранения, что означает, что его деструктор не будет вызываться неявно. Как и выше, также не обязательно явно вызывать деструктор, если программа не требует каких-либо побочных эффектов, которые могут быть выполнены деструктором.

Несмотря на то, что срок службы b закончился тот факт, что b Наличие автоматической длительности хранения означает, что его деструктор будет неявно вызываться, когда поток управления выходит из области видимости. Вызов деструктора для объекта, срок жизни которого истек, является частным случаем запрета на использование объекта, срок жизни которого истек, согласно пункту 6 §3.8, который запрещает вызов нестатической функции-члена-члена объекта, время жизни которого имеет закончилась, но чье хранилище еще не было повторно использовано или освобождено.

По этой причине поведение примера программы не определено.

Но параграф 7 этого раздела предоставляет механизм, позволяющий программе избежать неопределенного поведения путем воссоздания другого объекта того же типа в том же месте:

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

(7.1) - хранилище для нового объекта точно перекрывает место хранения, которое занимал исходный объект, и

(7.2) - новый объект того же типа, что и исходный объект (без учета cv-квалификаторов верхнего уровня), и

(7.3) - тип исходного объекта не является const-квалифицированным, и, если тип класса, не содержит какого-либо нестатического члена данных, тип которого является const-квалифицированным или ссылочным типом, и

(7.4) - исходный объект был наиболее производным объектом (1.8) типа T, а новый объект - наиболее производным объектом типа T (то есть они не являются подобъектами базового класса).

Итак, в моей интерпретации следующий фрагмент определил бы поведение:

class T { };
struct B {
    ~B();
};
void h() {
    B b;
    new (&b) T;
    new (&b) B; /* recreate a B so that it can be destructed */
}

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

Другие вопросы по тегам