Когда RVO должен ударить-?

Из следующего кода, Если 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/

8
задан James McNellis 16 July 2010 в 23:25
поделиться

4 ответа

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
}
9
ответ дан 5 December 2019 в 10:41
поделиться

Вы, кажется, неправильно понимаете 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;
}
1
ответ дан 5 December 2019 в 10:41
поделиться

Я не «Не знаю полных условий, но я считаю, что вы возвращаете параметр, а не экземпляр, созданный в функции, вызывает проблему в вашем примере.

Для меня следующее показало тот же адрес для обоих:

#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

CodePad о странице Документы, которые для него используют -fno-Elide-конструкторов для C ++ Отказ Документация для этой опции формирует состояние страницы G ++:

Стандарт C ++ позволяет внедрить, чтобы пропустить создание временный, который используется только для инициализации другого объекта тот же тип. Указание этой опции отключает эту оптимизацию и силы G ++, чтобы вызвать конструктор копирования во всех случаях.

На моей машине компиляция с -FNO-Elide-конструкторов предотвращает RVO, но компиляцию без него.

2
ответ дан 5 December 2019 в 10:41
поделиться

Правильный ответ: «Всякий раз, когда компилятор радует». Такое поведение не обязано (но разрешено) по стандарту, а точные условия, в которых он пинает в зависимости от компилятора к компилятору и версии для версии.

Как общее правило, компилятор является умнее, чем вы, и работаете в ваших интересах. Не подвергайте сомнению.

Рекомендации RValue в C ++ 0x - это ручная версия RVO.

Редактировать: Глядя ближе к вашему коду, вы определенно недоразумеете от RVO. Поскольку ваш параметр представляет собой ссылку, нет способа возврата функции не может иметь тот же адрес.

4
ответ дан 5 December 2019 в 10:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: