2013-09-06 3 views
7
vector<int> f(const vector<int>& v) 
{ 
    vector<int> ret(v.size()); 
    fill(ret.begin(), ret.end(), 123); 
    copy(v.begin(), v.end(), ret.begin()); 
    return ret; 
} 

int main() 
{ 
    vector<int> v(10); 
    v = f(v); 
} 

Если для f применяется функция value value, то локальная переменная ret имеет тот же адрес, что и v в main. Но если это так, заполнение ret приведет к удалению данных в v перед копией. Код правильный без RVO, и оптимизация не должна нарушать поведение.Как это работает с Оптимизацией возвращаемого значения?

Является ли это безопасным или я не понимаю RVO правильно?

+2

Существует две различные формы оптимизации возврата: копия из 'ret' во временное, чтобы вернуться из' f', а копия из этого временного в 'v'. Только первый разрешен здесь. – dyp

+0

Возможно, компилятор будет оптимизировать всю линию заполнения – OllieB

+0

@OllieB Возможно, но это был просто простой пример, который я составил. –

ответ

5

Что происходит:

На стороне вызывающего абонента, возврат предусмотрен слот, который может содержать результат, что означает, что абонент предоставляет памяти для переменного типа std::vector<int>. Он ожидает, что вызываемый метод построит значение и сам отвечает за вызов деструктора, когда результат больше не используется и освобождает память (при необходимости он, вероятно, просто живет в стеке).

Вызванная функция (которая может жить в другой единице трансляции!) Будет, без NRVO, так это:

  • Обеспечить слот памяти для ret.
  • Построить локальную переменную ret в этом слоте памяти.
  • Сделайте нужный материал ...
  • Копировать-построить возвращаемое значение в предоставленном слоте памяти путем копирования ret.
  • Звонок ret Деструктор.

Теперь, с NRVO, решение для оптимизации, это может быть сделано в блоке перевода вызываемой функции. Он преобразует вышеуказанное значение в:

  • Построить ret в память обратного хода метода.
  • Сделайте что-нибудь ...

Нет необходимости делать что-нибудь еще, как память принадлежит и деструктор вызывается вызывающим абонентом и потому, что оптимизация является прозрачным для вызывающего абонента :)

Это, конечно, не может устранить присваивание в v в вашем примере. Если вы сохраняете результат в другой переменной, например.

std::vector<int> w = f(v); 

NRVO построит ret непосредственно в память w «ы (как это будет принят в качестве слота возврата к f).

+0

RVO никогда не может удалить копию задания? –

+0

@NeilKirk No. Операция назначения всегда выполняется. Только прямая инициализация переменной (которая имеет синтаксис '=') может сделать это, но истинное присваивание не может быть оптимизировано с (N) RVO. –

5

код правильно, ваше понимание РВО не является - в частности, это:

the local variable ret shares the same address as v 

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

Это выглядит следующим образом:

  create variable `ret` 
        | 
copy ret to a temporary before returning 
        | 
     assign the temporary to v 

NRVO (в данном случае) будет пропустить вторую часть.

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

0

RVO касается строительства новых объектов. Очевидно, что в основном, компилятор не может передать v в качестве адреса возвращаемого значения, поскольку функция построить новый vector<int> в этом адреса, и v уже построен. Таким образом, он будет передавать адрес временного. RVO относится к тому, что происходит в функции : без RVO компилятор будет строить ret и , затем скопируйте его в адрес, переданный как скрытый аргумент . На сайте вызова, если используется возвращаемое значение , чтобы (скопировать) построить объект, тогда компилятор пропустит копию временного объекта в новый объект и просто передаст адрес объекта, который будет сконструирован. Если возвращаемое значение равно , но не используется как аргумент конструктора копирования, то не так много, что может сделать компилятор. Вам нужен объект правильный тип, поэтому он должен генерировать временное.

Смежные вопросы