15 Special member functions [special]

15.2 Temporary objects [class.temporary]

Создаются временные объекты

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

  • при необходимости реализации для передачи или возврата объекта тривиально копируемого типа (см. ниже) и

  • когда throwing an exception. [ Note: Время жизни объектов исключения описано в [except.throw]. ] end note

Даже когда создание временного объекта не оценивается (пункт [expr]), все семантические ограничения должны соблюдаться, как если бы временный объект был создан, а затем уничтожен. [ Note: Это включает в себя accessibility и то, был ли он удален, для выбранного конструктора и для деструктора. Однако в частном случае операнда a decltype-specifier([expr.call]) временное значение не вводится, поэтому вышеизложенное не применяется к такому prvalue. ]end note

Материализация временного объекта обычно откладывается на максимально возможный срок, чтобы избежать создания ненужных временных объектов. [ Note: Материализованы временные объекты:

end note] [ Example: Рассмотрим следующий код:

class X {
public:
  X(int);
  X(const X&);
  X& operator=(const X&);
  ~X();
};

class Y {
public:
  Y(int);
  Y(Y&&);
  ~Y();
};

X f(X);
Y g(Y);

void h() {
  X a(1);
  X b = f(X(2));
  Y c = g(Y(3));
  a = f(a);
}

X(2) строится в пространстве, используемом для хранения f()аргумента, и Y(3) создается в пространстве, используемом для хранения g()аргумента. Точно так же f()результат создается непосредственно в, b а g()результат создается непосредственно в c. С другой стороны, выражение a = f(a) требует временного значения для результата f(a), которое материализуется так, чтобы ссылочный параметр A​::​operator=(const A&) мог связываться с ним. ]end example

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

Когда реализация вводит временный объект класса, который имеет нетривиальный конструктор ([class.ctor], [class.copy]), она должна гарантировать, что конструктор вызывается для временного объекта. Точно так же деструктор должен вызываться для временного с нетривиальным деструктором ([class.dtor]). Временные объекты уничтожаются на последнем этапе оценки того, full-expression что (лексически) содержит точку, в которой они были созданы. Это верно, даже если эта оценка заканчивается выдачей исключения. В стоимости вычисление и побочные эффекты уничтожения временного объекта связаны только с полной экспрессией, а не с каким - либо конкретным подвыражением.

Есть три контекста, в которых временные объекты уничтожаются не в конце полного выражения. Первый контекст - это когда конструктор по умолчанию вызывается для инициализации элемента массива без соответствующего инициализатора ([dcl.init]). Второй контекст - это когда конструктор копирования вызывается для копирования элемента массива при копировании всего массива ([expr.prim.lambda.capture], [class.copy]). В любом случае, если у конструктора есть один или несколько аргументов по умолчанию, уничтожение каждого временного элемента, созданного в аргументе по умолчанию, упорядочивается до создания следующего элемента массива, если таковой имеется.

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

  • Временный объект, связанный со ссылочным параметром в a, function call сохраняется до завершения полного выражения, содержащего вызов.

  • Время жизни временной привязки к возвращаемому значению в функции return statement не продлевается; временное уничтожается в конце полного выражения в операторе возврата.

  • Временная привязка к ссылке в a new-initializerсохраняется до завершения полного выражения, содержащего new-initializer. [Example:

    struct S { int mi; const std::pair<int,int>& mp; };
    S a { 1, {2,3} };
    S* p = new S{ 1, {2,3} };   // Creates dangling reference
    

    end example] [ Note: Это может привести к появлению "висящей" ссылки, и в таком случае рекомендуется, чтобы реализации выдавали предупреждение. ] end note

Уничтожение временного объекта, время жизни которого не продлевается путем привязки к ссылке, выполняется до уничтожения каждого временного объекта, который ранее был сконструирован в том же полном выражении. Если время жизни двух или более временных объектов, к которым привязаны ссылки, заканчивается в одной и той же точке, эти временные объекты уничтожаются в этой точке в порядке, обратном завершению их построения. Кроме того, уничтожение временных связано с ссылками , должны учитывать порядок уничтожения объектов static, threadили automatic storage duration; то есть, если obj1 это объект с той же продолжительностью хранения, что и временный, и созданный до создания временного, временное должно быть уничтожено до того, как obj1 будет уничтожено; Если obj2 это объект с такой же продолжительностью хранения, что и временный, и созданный после создания временного, временное должно быть уничтожено после obj2 уничтожения.

[Example:

struct S {
  S();
  S(int);
  friend S operator+(const S&, const S&);
  ~S();
};
S obj1;
const S& cr = S(16)+S(23);
S obj2;

выражение S(16) + S(23) создает три временныхT1 объекта : первая временная для хранения результата выражения S(16), вторая временная T2 для хранения результата выражения S(23)и третья временная T3 для хранения результата сложения этих двух выражений. Затем временный T3 объект привязывается к ссылке cr. Не указано, был ли созданT1 или T2создан первым. В реализации, T1 которая была создана ранее T2, T2 должна быть уничтожена раньше T1. Временные T1 и T2 привязаны к ссылочным параметрам operator+; эти временные объекты уничтожаются в конце полного выражения, содержащего вызов operator+. Временная T3 привязка к ссылке cr уничтожается в концеcrжизненного цикла , то есть в конце программы. Кроме того, порядок T3 уничтожения учитывает порядок уничтожения других объектов со статической продолжительностью хранения. То есть, потому что obj1 построено раньше T3, и T3 построено раньше obj2, obj2 должно быть уничтожено раньше T3и T3 должно быть уничтожено раньше obj1. ]end example

Те же правила применяются к инициализации initializer_­list объекта ([dcl.init.list]) с его базовым временным массивом.