Оптимизация возвращаемого значения - C ++ - вызовы деструкторов - PullRequest
5 голосов
/ 12 февраля 2012

Следующий код вызывает деструктор 4 раза:

#include<iostream>
using namespace std;

class A{
   public:
   A(){cout<<"A"<<endl;}
   ~A(){cout<<"~A"<<endl;}
   A f(){cout<<"F"<<endl; A b; return b;}
};

int main(){
   A a,b;
   b=a.f();
}

ВЫВОД:

A
A
F
A
~A
~A
~A
~A

Может кто-нибудь объяснить, пожалуйста? Я думал, что должно быть только три вызова деструктора.

Ответы [ 6 ]

8 голосов
/ 12 февраля 2012

В main() есть два объекта, поэтому деструктор будет вызываться два раза только из-за них. Один объект в f(), поэтому деструктор будет называться один раз только из-за него. Всего 3 раза (что вы ожидаете, но читаете дальше ...)

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

В любом случае, просто увеличьте уровень оптимизации; Я уверен, что вы увидите не более 3 вызовов деструкторов.

3 голосов
/ 12 февраля 2012

В основном есть 2 объекта: A a,b;, один объект в теле функции f(): A b;, а затем есть временный объект, который копируется, и его копия сохраняется в b.

При возврате b в тело вашей функции сначала создается копия, затем локальный b уничтожается, затем копия присваивается переменной b, объявленной в main, а затем эта копия уничтожается.

Добавьте следующую строку в определение класса A и посмотрите сами:

A(const A&) { cout << "copying" << endl; }

С Именованная оптимизация возвращаемого значения , компилятор пытается устранить лишний конструктор Copyи Destructor вызывает , что означает, что local b из функции f() будет назначен переменной b в main без создания копии.Таким образом, с помощью RVO / NRVO в вашем случае создаются только 3 объекта.

Хотя есть способ избежать разрушения этой копии без RVO в вашем случае:

A a;
A b = a.f();

в этом случае копиявозвращаемого значения функции f() создается и сохраняется как переменная b.Это также означает, что оператор присваивания не вызывается, и в main создаются только 2 объекта: a и копия b, возвращаемая f().

Надеюсь, это поможет.

1 голос
/ 12 февраля 2012

Существует одно скрытое создание и уничтожение экземпляра A: когда вы возвращаетесь из функции f(), создается временная копия объекта b. Он присваивается b в main() и затем уничтожается.

1 голос
/ 12 февраля 2012

Ваш компилятор не оптимизировал его.Вы скомпилировали его с включенной оптимизацией?

Вот вывод того же кода, скомпилированного с помощью gcc:

A
A
F
A
~A
~A
~A
0 голосов
/ 12 февраля 2012

Локальная переменная в f копируется во временную переменную при возврате функции. Вот почему есть четыре вызова деструкторов. (Операция копирования вызывает конструктор копирования A(A&), а не ваш конструктор по умолчанию A(), следовательно, три A с.)

0 голосов
/ 12 февраля 2012

Вы не можете рассчитывать на то, что произойдет RVO. Вот почему вы никогда не должны помещать функциональную логику в деструкторы или конструкторы копирования (да, их тоже можно исключить).

Оптимизация возвращаемого значения - это то, что стандарт позволяет, но не применяет.

Без оптимизации или O2 я тоже получаю 4 деструктора callse.

С полной оптимизацией - Ох - я получаю только 3.

...