Ответ 1
Выяснить, что уже можно найти в комментариях:
Учитывая int f(Logger);
, когда вы пишете:
f(10);
это (концептуально) создает временный объект Logger
, строит параметр функции из этого временного объекта, вызывает функцию, разрушает параметр функции и, наконец, уничтожает временный объект.
Когда вы пишете:
f(f(10));
это (концептуально) создает временный объект Logger
, строит параметр функции из этого временного объекта, вызывает функцию, разрушает параметр функции, создает новый временный объект Logger
, используя первый результат вызова функции, строит функции из этого временного объекта, вызывает функцию, разрушает параметр функции и, наконец, уничтожает два временных объекта.
Я не буду писать его для случая f(f(f(10)));
.
Теперь эти два временных объекта можно опустить:
При выполнении определенных критериев реализация допускает опустить конструкцию копирования/перемещения объекта класса, даже если конструктор copy/move и/или деструктор для объекта имеют побочные эффекты. В таких случаях реализация рассматривает источник и цель пропущенной операции копирования/перемещения как просто два разных способа обращения к одному и тому же объекту, а уничтожение этого объекта происходит в более поздние времена, когда эти два объекта были бы разрушен без оптимизации. Это разрешение копирования/перемещения операции, называемые копией, разрешены в следующих случаях (которые могут быть объединены для устранения нескольких копий):
...
когда объект временного класса, который не был привязан к ссылке (12.2), был бы скопирован/перенесен в объект класса с тем же самым неавтоматизированным типом, операция копирования/перемещения может быть опущена путем построения временный объект непосредственно в цель пропущенной копии/перемещения
...
Поскольку параметр функции и временный объект имеют один и тот же тип, компилятору разрешено рассматривать их как один и тот же объект. Временный объект будет уничтожен на заключительном этапе, поэтому время жизни параметра не вступает в игру.
Однако, когда исключение копирования не выполняется, например, потому что вы не настроили компилятор, или потому, что в первую очередь нет копии, чтобы увидеть ее (см. ниже), тогда параметры функции действительно должны быть уничтожены, когда вы скажем, они должны быть, и вы должны увидеть "Destruct (...)" до того, как второй вызов функции начнется во всех соответствующих реализациях С++ 11.
Параметр может быть создан без временного использования с помощью фигурных скобок: вы можете повторно выполнить вызов как
f({f({f({10})})});
Здесь каждый параметр инициализируется списком, который в этом случае не включает временные объекты, и нет экземпляров для исключения. Это должно разрушить параметры функции, как только функция f
вернется, прежде чем f
будет вызван снова, во всех реализациях, совместимых с С++ 11, независимо от параметров командной строки -felide-constructors
и того факта, что компиляторы не делайте этого, это область, в которой они не соответствуют С++ 11.
Это не так просто, как это: CWG-выпуск 1880 гласит:
WG решила не указывать, уничтожены ли объекты параметров сразу после вызова или в конце полного выражения, к которому принадлежит вызов.
Это позволит точно, что теперь делают компиляторы: параметры могут быть уничтожены после окончания полного выражения после того, как последний f
вернулся. Точный буквальный текст С++ 11 не соответствует текущим компиляторам.