Это очень интересный вопрос. Верно, что формулировка о продолжительности динамического хранения и выражениях new
не исключает размещения-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:
Статическая, потоковая и автоматическая длительности хранения связаны с объектами, введенными декларациями и неявно созданными реализацией. Продолжительность динамического хранения связана с объектами, созданными с помощью нового выражения.
Я понимаю, что последнее предложение применимо только в том случае, если объект еще не охвачен первым предложением. Но пока это личная интерпретация. Так что единственное, что можно сказать наверняка, - это то, что в случае перекрытия потребуется дополнительная осторожность.
Итак, давайте более подробно рассмотрим Продолжительность динамического хранения [basic.stc.dynamic] / 1
Объекты могут создаваться динамически во время выполнения программы (...). Реализация C ++ обеспечивает доступ к динамической памяти и управление ею с помощью глобальных функций выделения, оператора new и оператора new [], а также функций глобального освобождения памяти, оператора delete и оператора delete [ ]. [Примечание: формы без распределения, описанные в 21.6.2.3, не выполняют выделение или освобождение. - конец примечания]
Второе предложение поясняет, что динамическая память означает выделение. Затем следует интересное примечание, которое относится именно к главе [new.delete.placement] / 1:
Эти функции зарезервированы; программа на C ++ не может определять функции, заменяющие версии в стандартной библиотеке C ++. Положения пункта 6.7.4 не применяются к этим формам зарезервированного размещения операторов new и operator delete.
Раздел 6.7.4 - это раздел basic.stc.dynamic. Это означает, что специальное выделение, используемое для нового размещения, не создает динамической памяти.
Тот факт, что динамическое хранение и продолжительность динамического хранения - это не одно и то же, затрудняет выражение всего этого:
- продолжительность динамического хранения означает, что вы должны заботиться о жизненном цикле объекта и удалять при необходимости
- динамическое хранение означает, что нет ограничений по продолжительности хранения.
- создание объекта продолжительности динамического хранения в другом месте, кроме динамического хранилища (и особенно в автоматическом хранилище), требует особой осторожности, так как вам нужно убедиться, что он уничтожен, пока хранилище доступно. Если вы просто замените объект на объект того же типа в новом месте размещения, вы получите выгоду от кода, который уничтожит объект при выходе из области видимости. Но в любом другом случае вам нужно будет проявить осторожность.
Здесь вы найдете онлайн-демонстрацию, чтобы поиграть с новым размещением и уничтожением и посмотреть, что происходит, когда охватывающий объект выходит за пределы области видимости. Он использует Tracer
класс, который лучше int
выделяет различные случаи (включая удаление предыдущего объекта перед вызовом нового размещения).
Заключение: я думаю, что нельзя избежать некоторой двусмысленности и замкнутости ни в одном стандарте с такой долгой историей и с таким большим количеством участников. Но в этом случае вы можете видеть, что сам вопрос имеет больше аспектов, чем вы ожидали в первую очередь.
person
Christophe
schedule
17.02.2019