6 Basic concepts [basic]

6.8 Object lifetime [basic.life]

lifetime Объект или ссылок является средой свойства объекта или ссылки. Считается, что объект имеет non-vacuous initialization тип класса или агрегата и он или один из его подобъектов инициализируется конструктором, отличным от тривиального конструктора по умолчанию. [ Note: Инициализация с помощью тривиального конструктора копирования / перемещения не является пустой инициализацией. ] Время жизни объекта типа начинается, когда: end note T

  • T получается хранилище с надлежащим выравниванием и размером для типа , и

  • если объект имеет непустую инициализацию, его инициализация завершена,

за исключением того, что если объект является членом объединения или его подобъектом, его время жизни начинается только в том случае, если этот член объединения является инициализированным членом в объединении ([dcl.init.aggr], [class.base.init]) или как описано в [class.union]. Время жизни объекта o типа T заканчивается, когда:

  • если T это тип класса с нетривиальным деструктором ([class.dtor]), запускается вызов деструктора, или

  • память, которую занимает объект, освобождается или повторно используется объектом, который не вложен в o ([intro.object]).

Время жизни ссылки начинается после завершения ее инициализации. Время жизни ссылки заканчивается, как если бы она была скалярным объектом.

[ Note: [class.base.init] описывает время жизни базовых и членских подобъектов. ] end note

Свойства, приписываемые объектам и ссылкам в настоящем международном стандарте, применяются к данному объекту или ссылке только в течение его срока службы. [ Note: В частности, до начала жизненного цикла объекта и после его окончания существуют значительные ограничения на использование объекта, как описано ниже, в [class.base.init] и в [class.cdtor]. Кроме того, поведение строящегося и разрушаемого объекта может отличаться от поведения объекта, время существования которого началось и не закончилось. [class.base.init] и [class.cdtor] описывать поведение объектов на этапах строительства и разрушения. ] end note

Программа может закончить время жизни любого объекта, повторно используя память, которую занимает объект, или явно вызвав деструктор для объекта типа класса с нетривиальным деструктором. Для объекта типа класса с нетривиальным деструктором программе не требуется явно вызывать деструктор перед повторным использованием или освобождением памяти, занимаемой объектом; однако, если нет явного вызова деструктора или если a delete-expression не используется для освобождения хранилища, деструктор не должен вызываться неявно, и любая программа, которая зависит от побочных эффектов, производимых деструктором, имеет неопределенное поведение.

До того, как время жизни объекта началось, но после того, как хранилище, которое будет занимать объект, было выделено41 или, после того, как время жизни объекта закончилось и до того, как хранилище, которое занимал объект, будет повторно использовано или освобождено, любой указатель, который представляет адрес место хранения, где будет или находился объект, может быть использовано, но только ограниченным образом. Для объекта, находящегося в стадии строительства или разрушения, см [class.cdtor]. В противном случае такой указатель относится к выделенному хранилищу ([basic.stc.dynamic.deallocation]), и использование указателя, как если бы указатель имел тип void*, является четко определенным. Косвенное обращение через такой указатель разрешено, но результирующее значение lvalue можно использовать только ограниченными способами, как описано ниже. Программа имеет неопределенное поведение, если:

  • объект будет или имел тип класса с нетривиальным деструктором, а указатель используется как операнд a delete-expression,

  • указатель используется для доступа к нестатическому члену данных или вызова нестатической функции-члена объекта, или

  • указатель неявно преобразуется ([conv.ptr]) в указатель на виртуальный базовый класс, или

  • указатель используется в качестве операнда static_­cast, за исключением того, когда преобразование является указателем cv void, или указатель , cv void а затем на указатель cv char, cv unsigned charили cv std​::​byte ([cstddef.syn]), или

  • указатель используется как операнд a dynamic_­cast.

[Example:

#include <cstdlib>

struct B {
  virtual void f();
  void mutate();
  virtual ~B();
};

struct D1 : B { void f(); };
struct D2 : B { void f(); };

void B::mutate() {
  new (this) D2;    // reuses storage — ends the lifetime of *this
  f();              // undefined behavior
  ... = this;       // OK, this points to valid memory
}

void g() {
  void* p = std::malloc(sizeof(D1) + sizeof(D2));
  B* pb = new (p) D1;
  pb->mutate();
  *pb;              // OK: pb points to valid memory
  void* q = pb;     // OK: pb points to valid memory
  pb->f();          // undefined behavior, lifetime of *pb has ended
}

end example]

Точно так же до того, как время жизни объекта началось, но после того, как было выделено хранилище, которое будет занимать объект, или после того, как время жизни объекта закончилось и до того, как хранилище, которое занимал объект, будет повторно использовано или освобождено, любое значение glvalue, которое относится к исходный объект можно использовать, но только ограниченным образом. Для объекта, находящегося в стадии строительства или разрушения, см [class.cdtor]. В противном случае такое glvalue относится к выделенному хранилищу ([basic.stc.dynamic.deallocation]), и использование свойств glvalue, которые не зависят от его значения, четко определено. Программа имеет неопределенное поведение, если:

  • glvalue используется для доступа к объекту, или

  • glvalue используется для вызова нестатической функции-члена объекта, или

  • glvalue привязан к ссылке на виртуальный базовый класс ([dcl.init.ref]) или

  • glvalue используется как операнд a dynamic_­cast или как операнд typeid.

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

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

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

  • тип исходного объекта не квалифицируется как константа, и, если это тип класса, не содержит каких-либо нестатических членов данных, чей тип квалифицируется как константный или ссылочный тип, и

  • исходный объект был most derived object типа a, T а новый объект является наиболее производным объектом типа T (то есть они не являются подобъектами базового класса).

[Example:

struct C {
  int i;
  void f();
  const C& operator=( const C& );
};

const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();                 // lifetime of *this ends
    new (this) C(other);        // new object of type C created
    f();                        // well-defined
  }
  return *this;
}

C c1;
C c2;
c1 = c2;                        // well-defined
c1.f();                         // well-defined; c1 refers to a new object of type C

end example] [ Note: Если эти условия не выполняются, указатель на новый объект может быть получен из указателя, представляющего адрес его хранилища, путем вызова std​::​launder ([support.dynamic]). ]end note

Если программа завершает время жизни объекта типа T с помощью static, threadили automatic storage duration и если T имеет нетривиальный деструктор,42 программа должна гарантировать, что объект исходного типа занимает то же место хранения, когда имеет место неявный вызов деструктора; в противном случае поведение программы не определено. Это верно, даже если выход из блока произошел с исключением. [Example:

class T { };
struct B {
   ~B();
};

void h() {
   B b;
   new (&b) T;
}                               // undefined behavior at block exit

end example]

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

struct B {
  B();
  ~B();
};

const B b;

void h() {
  b.~B();
  new (const_cast<B*>(&b)) const B;     // undefined behavior
}

end example]

В этом разделе «до» и «после» относятся к отношению «happens before». [ Note: Следовательно, неопределенное поведение возникает, если на объект, который создается в одном потоке, ссылаются из другого потока без адекватной синхронизации. ] end note

Например, перед построением глобального объекта типа класса не POD ([class.cdtor]).

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