Почему Visual C++ не выполняет оптимизацию возвращаемого значения для самого простого кода?

Разве Visual C++ не выполняет оптимизацию возвращаемого значения?

#include <cstdio>
struct Foo { ~Foo() { printf("Destructing...\n"); } };
Foo foo() { return Foo(); }
int main() { foo(); }

Я компилирую и запускаю его:

cl /O2 test.cpp
test.exe

И печатает:

Уничтожение...
Уничтожение...

Почему не выполняет РВО?


person user541686    schedule 30.07.2012    source источник
comment
Возможно, вы захотите спросить Microsoft, а не StackOverflow...   -  person David Rodríguez - dribeas    schedule 31.07.2012
comment
@DavidRodríguez-dribeas: В документация Microsoft говорит, что они могут выполнять named RVO (что намного сложнее), но мне не удалось заставить работать ни NRVO, ни простой RVO. Поэтому я чувствую, что делаю что-то не так, поскольку, если бы они не поддержали это, они бы не упомянули об этом (надеюсь...)   -  person user541686    schedule 31.07.2012
comment
@Mehrdad: у вас есть ссылка на документ от Microsoft?   -  person Chris Dargis    schedule 31.07.2012
comment
Возможно, компилятор дважды вызывает оператор печати, но по-прежнему создает только один объект.   -  person Chris Dargis    schedule 31.07.2012
comment
@DougRamsey: лол, нет, это невозможно и не имеет никакого смысла. Джеймс знал причину — я случайно сказал ему, что его решение не работает (потому что я случайно протестировал его на отладочной сборке), а затем он удалил комментарий. Но это было правильно. Теперь я просто жду, когда он опубликует это как ответ... это действительно странно. :)   -  person user541686    schedule 31.07.2012
comment
Я отозвал свой комментарий, потому что у меня была альтернативная гипотеза, которая оказалась неверной (я думал, что вместо RVO может происходить построение хода, но это не так). Я бы рекомендовал открыть сообщение об ошибке в Microsoft Connect, если проблема важна для вас. Поскольку проблема, по-видимому, затрагивает только те типы классов, у которых нет нетривиальных конструкторов, я не уверен, что это огромная проблема (а поскольку RVO — необязательная оптимизация, это не проблема соответствия), но о ней все же стоит сообщить.   -  person James McNellis    schedule 31.07.2012
comment
@JamesMcNellis: Спасибо за информацию. Я только что попытался сообщить об ошибке, но когда я загружаю расширение, оно говорит, что манифест недействителен. Я не фанат отправки отчетов об ошибках в MS только потому, что это так утомительно... :\   -  person user541686    schedule 31.07.2012


Ответы (1)


Когда я тестирую это:

#include <iostream>
struct Foo { 
    Foo(Foo const &r) { std::cout << "Copying...\n"; }
    ~Foo() { std::cout << "Destructing...\n"; }
    Foo() {}
};

Foo foo() { return Foo(); }

int main() { Foo f = foo(); }

...вывод, который я получаю:

Destructing...

Нет вызова конструктора копирования и только один деструктор.

person Jerry Coffin    schedule 30.07.2012
comment
Хм... не могли бы вы объяснить, в чем разница между этим кодом и моим кодом? - person user541686; 31.07.2012
comment
@Mehrdad: Каким-то образом сгенерированный компилятором конструктор по умолчанию, кажется, запрещает [N] RVO. Как только вы добавите свой собственный ctor по умолчанию, вы получите работающий [N]RVO (например, если вы добавите и вызовете: Foo bar() { Foo f; return f; }, вы просто получите еще один вызов деструктора, так что NRVO тоже работает). - person Jerry Coffin; 31.07.2012
comment
@Mehrdad: Похоже, RVO рассматривается только тогда, когда существует определяемый пользователем конструктор (вероятно, потому, что именно здесь он изначально имел значение), и по какой-то причине он не учитывается везде. - person GManNickG; 31.07.2012
comment
Конструктор не обязательно должен быть объявлен пользователем: заставляя Foo иметь нетривиальное значение по умолчанию, или конструктор копирования также повторно активирует RVO (например, дает ему элемент данных типа std::string). - person James McNellis; 31.07.2012
comment
@JamesMcNellis: :O Где ты всему этому научился?! Я никогда не видел эту информацию раньше... - person user541686; 31.07.2012
comment
Итог: компилятор беспокоится об устранении копий только тогда, когда есть хотя бы некоторая вероятность того, что копирование достаточно дорого, чтобы его стоило устранять. - person Jerry Coffin; 31.07.2012
comment
@Ed S.: Также помогает иметь доступ к исходному коду компилятора. - person Xander Tulip; 31.07.2012
comment
@XanderTulip: я не знал, что он работал на MS в команде VS C++: D. Думаю, это немного помогло бы. - person Ed S.; 31.07.2012