2013-11-07 2 views
15

Я понимаю, что с любой другой переменной тип параметра определяет взаимодействие между параметром и его аргументом. Мой вопрос заключается в том, что объясняет, почему вы ссылаетесь на параметр и почему вы этого не сделали? Почему некоторые параметры параметров ссылки, а некоторые нет? Не могли ли вы понять преимущества этого, может кто-нибудь объяснить?C++: Аргумент «Передано по ссылке»

+0

Создать вектор, содержащий 2gB данных. Теперь передайте его функции ... миллион раз. Я рекомендую этот вопрос. Обычно он начинается с «Не являются ли ссылки и указатели одинаковыми?» – WhozCraig

+0

, так полезно ли всегда всегда ссылаться на параметры? или это не очень умная вещь? – Tyler

+0

Нет Иногда существует определенная цель для передачи по значению. Это очень ситуационная ситуация. Некоторые из этих ситуаций могут быть чрезвычайно утонченными. – WhozCraig

ответ

44

Возможность пройти по ссылке, существует по двум причинам:

  1. Для того, чтобы изменить значение аргументов функции
  2. Чтобы избежать делать копии объекта по соображениям производительности

Пример для изменение аргумента

void get5and6(int *f, int *s) // using pointers 
{ 
    *f = 5; 
    *s = 6; 
} 

это может использоваться как :

int f = 0, s = 0; 
get5and6(&f,&s);  // f & s will now be 5 & 6 

ИЛИ

void get5and6(int &f, int &s) // using references 
{ 
    f = 5; 
    s = 6; 
} 

это может быть использовано как:

int f = 0, s = 0; 
get5and6(f,s);  // f & s will now be 5 & 6 

При переходе по ссылке, мы передать адрес переменной. Передача по ссылке аналогична передаче указателя - только адрес передается в обоих случаях.

Для например:

void SaveGame(GameState& gameState) 
{ 
    gameState.update(); 
    gameState.saveToFile("save.sav"); 
} 

GameState gs; 
SaveGame(gs) 

ИЛИ

void SaveGame(GameState* gameState) 
{ 
    gameState->update(); 
    gameState->saveToFile("save.sav"); 
} 

GameState gs; 
SaveGame(&gs); 


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

  1. Объект, передаваемые функции огромен (я использовал бы вариант указателя здесь, так что абонент знает, что функция может изменить значение переменного)
  2. функцию можно было бы назвать много раз (например.в петле)

Также, читайте на const ссылки. Когда он используется, аргумент не может быть изменен в функции.

1

Плюсы использования pass by reference: Вам не нужно создавать копию данных, которые вы передаете только указателю на нее в памяти. (огромный выигрыш в производительности, если у вас был массивный объект, который вы проходили). Вы можете «вернуть» несколько значений. Я знаю, что некоторые функции в c/C++ возвращают число, а один из параметров - указатель на данные, которые обрабатываются get.

Просьба использовать проход по ссылке: Вы должны быть осторожны, изменяя переданные данные, поскольку это может вызвать побочные эффекты, которые вы можете или не захотите.

1

Посредством ссылки в равной степени вручную передать переменную указателем, но по ссылке не позволит пользователю обрабатывать указатель «легко испортить».

19

This article helped me a lot.

Пожалуйста, забудьте про указатели на данный момент. И возьмите это с солью.

Ссылка объект. Когда вы проходите по ссылке, вы передаете объект.

При передаче по значению передается копия объекта; другой объект. Он может иметь то же самое состояние, но это другой экземпляр; клон.

Таким образом, это может иметь смысл, чтобы пройти по ссылке, если вы:

  • необходимо изменить объект внутри функции
  • не нужно (или хотят), чтобы изменить на объект, но хотелось бы избежать копирования только для передачи функции. Это будет ссылка const.

И это может иметь смысл передавать по значению, если вы:

  • хотите начать с идентичноготвин и оставить оригинальный близнеца ненарушенных
  • не волнует о стоимости копирования объекта (например, я не передал бы int по ссылке , если только Я не хотел его изменять).

Вот, посмотрите на этот код:

#include<iostream> 

struct Foo { 
    Foo() { } 
    void describe() const { 
    std::cout<<"Foo at address "<<this<<std::endl; 
    } 
}; 

void byvalue(Foo foo) { 
    std::cout<<"called byvalue"<<std::endl; 
    foo.describe(); 
} 

void byreference(Foo& foo) { 
    std::cout<<"called byreference"<<std::endl; 
    foo.describe(); 
} 

int main() { 
    Foo foo; 
    std::cout<<"Original Foo"<<std::endl; 
    foo.describe(); 
    byreference(foo); 
    byvalue(foo); 
} 

И скомпилировать его так: g++ example.cpp

Выполнить это: ./a.out

И проверьте вывод (фактические адреса могут будет отличаться на вашем компьютере, но точка останется):

Original Foo 
Foo at address 0x7fff65f77a0f 
called byreference 
Foo at address 0x7fff65f77a0f 
called byvalue 
Foo at address 0x7fff65f779f0 

Обратите внимание, что адрес called byreference совпадает с адресом Original Foo (оба являются 0x7fff65f77a0f). И обратите внимание, как called byvalue адрес другой (это 0x7fff65f779f0).

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

#include<iostream> 
#include<unistd.h> // for sleeping 

struct Foo { 
    Foo() { } 
    Foo(const Foo&) { 
    sleep(10); // assume that building from a copy takes TEN seconds! 
    } 
    void describe() const { 
    std::cout<<"Foo at address "<<this<<std::endl; 
    } 
}; 

void byvalue(Foo foo) { 
    std::cout<<"called byvalue"<<std::endl; 
    foo.describe(); 
} 

void byreference(Foo& foo) { 
    std::cout<<"called byreference"<<std::endl; 
    foo.describe(); 
} 

int main() { 
    Foo foo; 
    std::cout<<"Original Foo"<<std::endl; 
    foo.describe(); 
    byreference(foo); 
    byvalue(foo); 
} 

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

Original Foo 
Foo at address 0x7fff64d64a0e 
called byreference 
Foo at address 0x7fff64d64a0e # this point is reached "immediately" 
called byvalue # this point is reached TEN SECONDS later 
Foo at address 0x7fff64d64a0f 

Таким образом, код предназначен преувеличивать стоимость копии: когда вы позвонили по ссылке, эта стоимость НЕ была произведена. Когда вы звонили по стоимости, вам пришлось ждать десять секунд.

Примечание: мой код был скомпилирован в OS X 10.7.4 с использованием GCC 4.8.1. Если вы находитесь в окнах, вам может понадобиться что-то отличное от unitsd.h, чтобы сделать работу вызова sleep.

Возможно, это помогает.

+0

Спасибо, я был так смущен, когда «проходил по ссылке», называемый частным копиром ... – Kyslik

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