C++: возврат по ссылке для возврата по значению

Я читал книгу Майерса и наткнулся на элемент при возврате по ссылке/указателю против значения. Дело в том, что если наша функция, например, такая:

ClassA& AddSomething(ClassA classA)
{
  ClassA tempClassA;
  //... do something on tempClassA
  return tempClassA;
}

Это не сработает, потому что мы возвращаем ссылку на объект, который был создан в стеке, и теперь, когда функция выполнена, он мертв.

Он дает два решения:

  1. Использование локального статического ClassA внутри функции. У этого есть свои проблемы, но, по крайней мере, мы можем быть уверены, что объект существует.
  2. Вернуть как объект:

    ClassA AddSomething(ClassA classA)
    {
      ClassA tempClassA;
      //... do something on tempClassA
      return tempClassA;
    }
    

Теперь, если я должен сделать:

ClassA obj1;
ClassA obj2 = AddSomething(obj1);

Моя путаница сейчас при выполнении этой строки:

  1. Создается «копия» tempClassA и передается конструктору копирования ClassA (для инициализации obj2)? ИЛИ
  2. tempClassA передается конструктору копирования ClassA, потому что конструктор копирования принимает ссылку.

Таким образом, в конструктор копирования передается ссылка на tempClassA (который был создан в стеке внутри функции) или ссылка на копию tempClassA.

Кроме того, у меня есть еще один вопрос: я читал, что если я получу ссылку на локальную переменную функции, в этом случае локальная переменная не будет удалена. Например,

ClassA & classRef = AddSomething(obj1);

В этом случае, если AddSomething() возвращает ссылку, то classRef не будет указывать на удаленную ссылку, потому что локальная переменная будет сохранена. Я правильно это понял?


person madu    schedule 30.08.2012    source источник
comment
Взгляните на копировать исключение.   -  person juanchopanza    schedule 30.08.2012


Ответы (3)


Когда объект возвращается по значению, происходит две копии: одна из локальной переменной в возвращаемое значение, а другая из возвращаемого значения в целевой объект. Однако реализация может опустить одну или обе эти копии; в первом случае это называется оптимизацией возвращаемого значения (RVO), а копировать elision во втором.

Object some_function() {
    return Object();    // copy Object() into return value; candidate for RVO
}
Object another_function() {
    Object obj;
    return obj;         // copy obj into return value; candidate for NRVO
}
Object result = some_function();   // copy return value into result; candidate for copy elision

Вторая вышеприведенная функция является кандидатом на тип уточнения RVO, который называется named оптимизация возвращаемого значения; простейшая форма RVO применяется только к операторам return, которые создают возвращаемое значение на месте.

Что касается вашего второго вопроса, продление срока службы применяется только к ссылкам const на объекты, возвращаемые по значению; ваш код во втором вопросе не продлит срок службы любого объекта. Дополнительные сведения см. в разделе Возврат временного объекта и привязка к константной ссылке. .

person ecatmur    schedule 30.08.2012

В худшем случае вы правы: копия tempClassA передается конструктору копирования. Но компиляторам разрешено удалять эту копию и создавать результат вместо формы tempClassA. Это известно как «Оптимизация возвращаемого значения» или RVO. Я не знаю компилятора, который этого не делает.

person Pete Becker    schedule 30.08.2012

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

const ClassA& classRef = AddSomething(obj1);

Потому что, если AddSomething возвращает локальный объект по ссылке, это будет висячая ссылка на несуществующий объект к тому времени, когда classRef сошлется на него.

person TommiT    schedule 30.08.2012