Понимание оптимизации возвращаемого значения и возврата временных рядов - С++ - программирование
Подтвердить что ты не робот

Понимание оптимизации возвращаемого значения и возврата временных рядов - С++

Пожалуйста, рассмотрите три функции.

std::string get_a_string()
{
    return "hello";
}

std::string get_a_string1()
{
    return std::string("hello");
}

std::string get_a_string2()
{
    std::string str("hello");
    return str;
}
  • Будет ли RVO применяться во всех трех случаях?
  • Можно ли вернуть временное значение, как в приведенном выше коде? Я считаю, что это нормально, так как я возвращаю его по значению, а не возвращаю ссылку на него.

Любые мысли?

4b9b3361

Ответ 1

В двух первых случаях будет проведена оптимизация RVO. RVO - старая функция, и большинство компиляторов поддерживает ее. Последний случай называется так называемым NRVO (Named RVO). Эта относительно новая особенность С++. Стандарт допускает, но не требует реализации NRVO (а также RVO), но некоторые компиляторы поддерживают его.

Вы можете больше узнать о RVO в 20-м номере книги Скотта Мейерса Более эффективный С++. 35 Новые способы улучшения ваших программ и дизайнов.

Здесь - хорошая статья о NRVO в Visual С++ 2005.

Ответ 2

Во-первых, вполне нормально возвращать временное значение, которое вы делаете. Он копируется, и хотя оригинал выходит за рамки, копия не будет делать этого и может быть безопасно использована вызывающим.

Во-вторых, все три случая на самом деле идентичны (поскольку в любом случае вы не имеете доступа к временному в третьем случае), и компилятор может даже выпустить один и тот же код для всех них. Следовательно, он может использовать RVO во всех трех случаях. Это полностью зависит от компилятора.

Ответ 3

Все случаи правильные. Все они построят временное и применит конструктор копирования возвращаемого типа. Обязательно, если нет конструктора копирования, код не будет выполнен.

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

Кстати, возвращение ссылки, конечно, возможно, как вы могли видеть в другом коде. То, что вы не должны делать, это вернуть ссылку t локальному объекту.

std::string& get_a_string2()
{
    std::string str("hello");
    return str; //error!
}

Будет выдавать ошибку времени компиляции, как вы знаете. Тем не менее,

std::string& get_a_string2(std::string& str)
{
    // do something to str
    return str; //OK
}

Будет отлично работать. В этом случае не предусмотрено строительство или копирование. Просто функция возвращает ссылку на свой аргумент.

Ответ 4

  • Это зависит от вашего компилятора - на какой платформе вы ссылаетесь? Лучший способ узнать - собрать очень небольшое тестовое приложение и проверить ASM, который производит ваш компилятор.

  • Да, все в порядке, хотя вы никогда не упоминаете, что вас беспокоит; скорость? стиль? вы можете использовать локальную временную привязку к константной ссылке - срок жизни временного будет расширен до срока службы ссылки - попробуйте и убедитесь сами! (Herb Sutter exaplins this здесь) См., Например, конец сообщения.

IMO, вы почти всегда лучше доверяете своему компилятору, чтобы оптимизировать свой код для вас. Очень мало случаев, когда вам нужно позаботиться об этом (очень низкий уровень кода - это одна такая область, где вы взаимодействуете с аппаратными регистрами).

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}