Срок хранения замененного подобъекта - PullRequest
0 голосов
/ 17 февраля 2019

Относительно кода ниже

int main()
{
    struct S { int i; } s { 42 };
    new (&s.i) int { 43 };
}

[basic.stc] / 2 говорит

Время динамического хранения связано с объектами, созданнымиnew-expression.

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

Вот тщательно разработанный пример, для которого есть формулировка, в которой говорится что-то интересное. [basic.stc.inherit] / 1 говорит:

Продолжительность хранения подобъектов и опорных членов равна продолжительности их полного объекта

и [intro.object] / 2 гарантирует, что созданный объект int является подобъектом s:

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

Итак, какая продолжительность хранения у вновь созданного объекта int?Динамический или автоматический?

1 Ответ

0 голосов
/ 17 февраля 2019

Этот вопрос очень интересный.Это правда, что формулировка о продолжительности динамического хранения и выражениях 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 [], а также оператор удаления глобальных функций удаления и оператор удаления [].[ Примечание: формы невыделения, описанные в 21.6.2.3, не выполняют распределение или освобождение.- примечание конца ]

Во втором предложении ясно, что динамическое хранение означает выделение.Затем следует интересное примечание, которое относится именно к главе [new.delete.placement] / 1 :

Эти функции зарезервированы;программа C ++ может не определять функции, которые заменяют версии в стандартной библиотеке C ++. Положения пункта 6.7.4 не применяются к этим зарезервированным формам размещения операторов new и operator delete.

Раздел 6.7.4 - это раздел basic.stc.dynamic .Это означает, что специальное распределение, используемое для размещения новых, не создает динамическое хранилище.

Тот факт, что динамическое хранилище и длительность динамического хранилища не являются одним и тем же, затрудняет выражение всего материала:

  • длительность динамического хранения означает, что вы должны позаботиться ожизненный цикл объекта и удаление при необходимости
  • динамического хранилища означает, что нет никаких ограничений на продолжительность хранения.
  • Создание объекта продолжительности динамического хранения в другом месте, чем в динамическом хранилище (и особенно в месте автоматического хранения), требует особой осторожности, так как вы должны убедиться, что он уничтожен, пока хранилище доступно.Если вы просто замените объект объектом того же типа в новом месте размещения, вы получите выгоду от кода, который уничтожит объект при выходе из области видимости.Но в любом другом случае вам нужно позаботиться.

Здесь онлайн-демонстрация , чтобы поиграть с новым размещением и разрушением, а также посмотреть, что происходит, когда окружающий объект выходит из области видимости.Он использует класс Tracer, который будет выделять лучше, чем int различные случаи (включая удаление предыдущего объекта перед вызовом нового размещения).

Заключение: Я думаю, что нельзя избежать некоторой двусмысленности и округлости ни в одном стандарте с такой длинной историей и с таким большим количеством участников.Но в этом случае вы можете видеть, что сам вопрос имеет больше аспектов, чем вы ожидали в первую очередь.

...