2015-01-07 2 views
-4

Для того, чтобы сделать мой вопрос ясно, я даю следующий пример:В чем разница между ссылкой класса и объектом класса, когда функция возвращает объект класса в C++?

#include <iostream> 


    class Abc 
    { 
     public: 
     int a; 
     int b; 
     int c; 
    }; 
    class Abc fun1() 
     { 
     Abc obj; 
     obj.a = 3; 
     obj.b = 4; 
     obj.c = 5; 
      return obj; 

     }; 

     int main() 
     { 
      Abc obj1; 
      obj1 = fun1(); 
      std::cout<<"obj1 address is "<<&obj1<<std::endl; 

      Abc &obj11 = fun1(); 
      std::cout<<"obj11 address is "<<&obj11<<std::endl; 



     return 0; 
} 

Как вы можете видеть, возвращаемое значение функции является объект класса, и когда вы вызываете эту функцию, чтобы создать объект класса, вы можете либо используйте объект класса obj1 или ссылку на класс obj11. Для меня они одинаковы, и мне было интересно, какая разница между ними и какая практика поощряется.

EDIT: Он может скомпилировать на Visual Studio 2010.

+4

Не следует компилировать? – Columbo

+0

Я думаю, что в декларации ссылок отсутствует 'const'. –

+0

его не компилируется.http: //ideone.com/QSrlb1 – Ankur

ответ

1
Abc &obj11 = fun1(); 

Эта линия делает программу плохо сформированной; спецификация C++ запрещает привязку временных ссылок к ссылке, которая не является const. Соответствующий компилятор C++ испускает ошибку. Предположительно, вы используете компилятор Microsoft Visual C++, который хорошо известен тем, что позволяет связывать временную ссылку с номером const, что противоречит спецификации C++.

const Abc &obj11 = fun1(); 

Эта линия будет хорошо сформирована, и это приведет к временной привязке к ссылке.

В любом случае при привязке временного к ссылке временное время продлевается до соответствия времени жизни ссылки, поэтому, когда ссылка выходит за пределы области действия, временная также будет уничтожена. Другими словами, в терминах семантики жизни это эквивалентно строке Abc obj1 = fun1(); . Если вы используете компилятор, который копирует копии, все копии будут удалены в обоих случаях. Если не eliding копии, то базовый вариант будет включать в себя один меньше копию:

  • значение случай, возвращенный объект будет скопирован в временный, а затем уничтожаются, и временные будут скопированы в obj1, а затем уничтожаются.
  • Ссылочный случай, возвращенный объект будет скопирован во временный, а затем уничтожен, а временный будет привязан к ссылке.

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

(Если вы заинтересованы, here is a test case с кодом слегка подправили от этого в вашем вопросе. Обратите внимание, что копии не принимаются в любом случае, если копия элизия не отключена.)


Обратите внимание, что это отличается от кода Abc obj1; obj1 = fun1(); в вашем вопросе. Я намеренно изменил его, потому что написанный вами код напрямую не сопоставим, поэтому сравнивать их не имеет смысла. Если вы перепишете его как Abc obj1 = fun1();, тогда можно сравнить две строки, потому что Abc obj1; obj1 = fun1(); включает в себя построение по умолчанию и затем назначение копии.

+0

* Обратите внимание, что достойный оптимизирующий компилятор ... * FWIW, 'Abc obj1; obj1 = fun1(); 'все еще вызывает вызов конструктора дважды (проверяется с помощью g ++ и clang ++), тогда как' const Abc & obj11 = fun1(); 'только один раз –

+0

@InnocentBystander Да, я просто обнаружил, что сам и редактирую. – cdhowie

+0

@InnocentBystander Мне любопытно, если вы явно отключили копирование, хотя, потому что на '-O2' я вообще не вижу никаких копий. – cdhowie

1

они не являются одинаковыми. в линии

obj1 = fun1(); 

fun1() создает объекты, то obj1 КОПИИ содержание его. поэтому у вас есть два объекта: один, анонимный, который больше нельзя использовать, и obj1, который является точной копией.

в строке

Abc &obj11 = fun1(); 

вы ловите объект fun1(), созданный который ссылка. теперь у вас есть только ОДИН объект, пойманный со ссылкой.

Извещение о том, что A a и A& a = b не совпадают. A a создает объект в стеке. A& a = b не создает другого объекта, он просто «ловит» один со ссылкой.

+3

* «A & a = b не создает другого объекта» * - На самом деле это зависит от того, копируете ли вы копии. Если вы не копируете копии, он все равно сделает копию; возвращенный объект будет скопирован во временный, а временный - привязан к ссылке. (И он по-прежнему не будет компилироваться на совместимом компиляторе C++ ...) – cdhowie

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