Срок хранения замененного подобъекта
Что касается кода ниже
int main()
{
struct S { int i; } s { 42 };
new (&s.i) int { 43 };
}
[basic.stc]/2 говорит
Динамическая продолжительность хранения связана с объектами, созданными выражением new.
Есть похожий вопрос, где было решено, что размещение new создает объекты с динамической длительностью хранения. Потому что нет формулировок, говорящих иначе, что было бы применимо к примеру в этом вопросе.
Вот тщательно разработанный пример, для которого есть формулировка, говорящая что-то интересное. [basic.stc.inherit] / 1 говорит:
Продолжительность хранения подобъектов и ссылочных членов равна продолжительности их полного объекта
и [intro.object]/2 гарантирует, что созданный int
объект является подобъектом s
:
Если объект создается в хранилище, связанном с подобъектом-членом или элементом массива e (который может или не может быть в пределах его времени жизни), созданный объект является подобъектом содержащего e объекта, если:
(требования выполнены, я не буду копировать их здесь)
Итак, какая продолжительность хранения вновь созданного int
объект имеет? Динамический или автоматический?
1 ответ
Этот вопрос очень интересный. Это правда, что формулировка о динамической продолжительности хранения и new
Выражения не исключают размещения новых.
Неоднозначность в формулировке обусловлена большим разнообразием случаев, которые необходимо охватить:
int main()
{
struct Simple { int i; } s { 42 };
new (&s.i) int { 43 }; // the lifecyle of the newly created object
// will auto, since Simple will be destroyed when
// going out of scope
struct Complex { char s[256]; } c;
Simple *p = new (&c.s) Simple; // the lifecycle of the newly created object
// is dynamic. You'll need to delete it in time.
// because compiler doesn't know about its true nature
// and memory will be lost when going out of scope
}
К счастью, стандарт достаточно точен, поэтому, если вы предоставите правильный код (т. Е. Не UB), каждый компилятор даст тот же результат.
Фактически, динамическое создание объекта (размещение нового) не обязательно подразумевает, что жизненный цикл объекта не зависит от области, в которой создается объект. Но это зависит от вас, чтобы убедиться, что объект будет уничтожен в должное время, и, следовательно, это рассматривается как динамическая продолжительность хранения.
Ключевым моментом здесь является распределение. Только выделение памяти может сделать продолжительность объекта действительно независимой от области, в которой он был создан. Это выражено в стандарте, но, возможно, не так ясно, как могло бы быть. Давайте начнем с полного предложения в basic.stc/2:
Статические, потоковые и автоматические сроки хранения связаны с объектами, представленными объявлениями и неявно созданными реализацией. Динамическая продолжительность хранения связана с объектами, созданными выражением new.
Здесь я понимаю, что последнее предложение применяется только в том случае, если объект еще не охвачен первым предложением. Но это личная интерпретация на данный момент. Так что единственное, что можно сказать наверняка, это то, что в случае совпадения требуется дополнительная осторожность.
Итак, давайте посмотрим более внимательно на динамическую продолжительность хранения [ basic.stc.dynamic ]/1
Объекты могут создаваться динамически во время выполнения программы (...). Реализация C++ обеспечивает доступ к динамическому хранилищу и управление им с помощью оператора глобальных функций выделения new и оператора new[], а также оператора удаления глобальных функций удаления и оператора удаления []. [ Примечание: формы невыделения, описанные в 21.6.2.3, не выполняют распределение или освобождение. - конец примечания ]
Второе предложение проясняет, что динамическое хранение означает распределение. Затем следует интересная заметка, которая относится именно к главе [new.delete.placement] / 1:
Эти функции зарезервированы; программа C++ может не определять функции, которые заменяют версии в стандартной библиотеке C++. Положения пункта 6.7.4 не применяются к этим зарезервированным формам размещения операторов new и operator delete.
Раздел 6.7.4 является разделом basic.stc.dynamic. Это означает, что специальное распределение, используемое для размещения новых, не создает динамическое хранилище.
Тот факт, что динамическое хранилище и длительность динамического хранилища не являются одним и тем же, делает весь материал сложным для выражения:
- Динамическая продолжительность хранения означает, что вы должны заботиться о жизненном цикле объекта и удалять при необходимости
- динамическое хранение означает, что нет никаких ограничений на продолжительность хранения.
- Создание объекта продолжительности динамического хранения в другом месте, чем в динамическом хранилище (и особенно в автоматическом хранилище), требует особой осторожности, поскольку необходимо убедиться, что он уничтожен, пока хранилище доступно. Если вы просто замените объект объектом того же типа в новом месте размещения, вы получите выгоду от кода, который уничтожит объект при выходе из области видимости. Но в любом другом случае вам нужно позаботиться.
Здесь онлайн-демонстрация, чтобы поиграть с новыми и разрушениями, и посмотреть, что происходит, когда окружающий объект выходит из области видимости. Он использует Tracer
класс, который будет выделяться лучше, чем int
различные случаи (включая удаление предыдущего объекта перед вызовом нового размещения).
Вывод: я думаю, что нельзя избежать некоторой двусмысленности и округлости в любом стандарте с такой длинной историей и с таким большим количеством участников. Но в этом случае вы можете видеть, что сам вопрос имеет больше аспектов, чем вы ожидали в первую очередь.