Я не программировал серьезно на C++ с третьего курса, потому разные тонкости уже подзабыл. Ни в сети, ни у Страуструпа ответа на вдруг возникший вопрос найти не могу. Вот небольшая программа:
#include
using namespace std;
class A {
public:
A() { cout << "A::A()" << endl; }
A(const A&) { cout << "A::A(const A&)" << endl; }
~A() { cout << "A::~A()" << endl; }
private:
A& operator = (const A&);
};
A FooBar() {
A tmp;
return tmp;
}
int main() {
A a;
A b = FooBar();
return 0;
}
Я всегда считал, что она отработает следующим образом.
- В строчке "A a;" вызовется конструктор по умолчанию
- Далее внутри функции "FooBar()" вызовется конструктор по умолчанию в строчке "A tmp;"
- Наконец, в строчке "A b = FooBar();" будет вызван конструктор копирования, который выполнит инициализацию объекта "b" объектом "tmp".
А вот оказывается, что конструктор копирования не вызывается здесь ни разу!
На печати я вижу вот что:
A::A()
A::A()
A::~A()
A::~A()
Пожалуйста, объясните мне, что происходит в строчке "A b = FooBar();"?
Кстати, если в "main()" я пишу "A b = a;", то на печати, как и ожидается, имею
A::A()
A::A(A&)
A::~A()
A::~A()
Использовались компиляторы g++ и xlC:
g++ -Wall -Wextra -O0 test.cpp
xlC -O0 test.cpp
Upd. Оказывается, я столкнулся с так называемой
Return value optimization.
Следующая программа (в ней модифицирована FooBar() и ее вызов) уже выдает, то, что ожидает всякий C++-пенсионер:
#include
using namespace std;
class A {
public:
A() { cout << "A::A()" << endl; }
A(A&) { cout << "A::A(A&)" << endl; }
A(const A&) { cout << "A::A(const A&)" << endl; }
~A() { cout << "A::~A()" << endl; }
private:
A& operator = (const A&);
};
A FooBar(bool b) {
A t1;
A t2;
if (b) return t1;
else return t2;
}
int main() {
A a;
A b = FooBar(true);
return 0;
}
Upd-2. В комментариях
пишут, что такое поведение можно отключить ключом -fno-elide-constructors.