Из следующего кода, Если RVO произошел, я ожидаю видеть, что 2 адреса указывают на то же местоположение, однако дело обстоит не так (мой компилятор MS VC9.0),
#include
#include
std::string foo(std::string& s)
{
std::cout << "address: " << (unsigned int)(&s) << std::endl;
return s;
}
int main()
{
std::string base = "abc";
const std::string& s = foo(base);
std::cout << "address: " << (unsigned int)(&s) << std::endl;
std::cout << s << std::endl;
return 0;
}
При каких условиях RVO должен происходить?
btw, я основываю свой вопрос на следующем обсуждении: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
RVO обычно применяется, когда вы возвращаете безымянный временный объект, но не, если вы возвращаете ранее созданный объект.
std::string foo() {
return std::string("hello world"); // RVO
}
std::string foo() {
std::string str("hello world");
bar();
return str; // Not RVO
}
std::string foo(std::string str) {
return str; // Not RVO
}
Более общей версией является NRVO (Named return value optimization - оптимизация по именованным значениям), которая также работает с именованными переменными.
std::string foo() {
std::string str("hello world");
bar();
return str; // NRVO
}
std::string foo(std::string str) {
return str; // Not NRVO, as far as I know. The string is constructed outside the function itself, and that construction may be elided by the compiler for other reasons.
}
std::string foo(std::string str) {
std::string ret;
swap(ret, str);
return ret; // NRVO. We're returning the named variable created in the function
}
Вы, кажется, неправильно понимаете RVO, попробуйте этот пример (на самом деле NRVO) :
std::string foo(const char* const s)
{
std::string out(s);
std::cout << "address: " << (void*)(&out) << std::endl;
return out;
}
int main()
{
std::string s = foo("abc");
std::cout << "address: " << (void*)(&s) << std::endl;
}
Я не «Не знаю полных условий, но я считаю, что вы возвращаете параметр, а не экземпляр, созданный в функции, вызывает проблему в вашем примере.
Для меня следующее показало тот же адрес для обоих:
#include <iostream>
#include <string>
std::string foo()
{
std::string s("rvo!");
std::cout << "address: " << (void *)(&s) << std::endl;
return s;
}
int main()
{
const std::string s = foo();
std::cout << "address: " << (void *)(&s) << std::endl;
std::cout << s << std::endl;
return 0;
}
, выполнении до комментариев Дарида
CodePad о странице Документы, которые для него используют -fno-Elide-конструкторов для C ++ Отказ Документация для этой опции формирует состояние страницы G ++:
Стандарт C ++ позволяет внедрить, чтобы пропустить создание временный, который используется только для инициализации другого объекта тот же тип. Указание этой опции отключает эту оптимизацию и силы G ++, чтобы вызвать конструктор копирования во всех случаях.
На моей машине компиляция с -FNO-Elide-конструкторов предотвращает RVO, но компиляцию без него.
Правильный ответ: «Всякий раз, когда компилятор радует». Такое поведение не обязано (но разрешено) по стандарту, а точные условия, в которых он пинает в зависимости от компилятора к компилятору и версии для версии.
Как общее правило, компилятор является умнее, чем вы, и работаете в ваших интересах. Не подвергайте сомнению.
Рекомендации RValue в C ++ 0x - это ручная версия RVO.
Редактировать: Глядя ближе к вашему коду, вы определенно недоразумеете от RVO. Поскольку ваш параметр представляет собой ссылку, нет способа возврата функции не может иметь тот же адрес.