Путаница в C ++

Я новичок в C ++ и сейчас изучаю его. У меня есть несколько вопросов ..

  1. В чем разница между void DoSomething (const Foo & foo) и void DoSomething (Foo foo)? Если мы не укажем &, то экземпляр Foo будет передан значение (не ссылка). Это будет то же самое, что и аргумент const + & in, за исключением отсутствия проверки во время компиляции. Итак, почему использование const + & становится лучшей практикой по сравнению с аргументом без & и const?

    В C # объект передается по ссылке, но, похоже, этого нет в C ++.

  2. В книге, которую я читаю, сказано, что функции-члены передают неявный параметр по ссылке.

    Может ли кто-нибудь дать мне образец неявного параметра и по ссылке? Я знаю, что если мы хотим передать объект по ссылке, нам нужно использовать & (например, Foo (Person & p)), но почему С ++ передает объект по ссылке для неявного параметра? Я читал, что неявный параметр в C ++ похож на Contructor (string str): strMemberVariable (str) {} ...

  3. Является ли массив единственным, что передается по ссылке в C ++?

  4. Почему я не могу использовать Foo fInstance в классе Foo?

Пример:

class Foo {

public:    
    Foo() { }

    Foo(const Foo& f) : fInstance(f) {   }  

    Foo fInstance;      
};

Заранее спасибо.


person Michael Sync    schedule 26.06.2010    source источник


Ответы (12)


1 В чем разница между void DoSomething (const Foo & foo) и void DoSomething(Foo foo)? Если мы не укажем &, то экземпляр Foo будет передан по значению (а не по ссылке). Это будет то же самое, что и аргумент const + & in, за исключением отсутствия проверки во время компиляции. Итак, почему использование const + & становится лучшей практикой по сравнению с аргументом без & и const?

В C # объект передается по ссылке, но, похоже, этого нет в C ++.

Есть несколько отличий в порядке важности:

  • Если объект Foo невозможно скопировать, нужно передать его по ссылке
  • Если объект Foo является базовым классом, вы должны получить его по ссылке, чтобы пользователи могли вызывать ваши функции с производными классами.
  • Значение фактического объекта может измениться, даже если у вас есть ссылка на него const.
  • Эффективность, копирование типов пользователей может быть дорогостоящим, но компиляторы могут быть достаточно умными, чтобы понять это, так что ...

2 В книге, которую я читаю, сказано, что функции-члены передают неявный параметр по ссылке.

Может ли кто-нибудь дать мне образец неявного параметра и по ссылке? Я знаю, что если мы хотим передать объект по ссылке, нам нужно использовать & (например, Foo (Person & p)), но почему С ++ передает объект по ссылке для неявного параметра? Я читал, что неявный параметр в C ++ похож на Contructor (string str): strMemberVariable (str) {} ...

Под неявным параметром следует понимать this, то есть сам объект. Он эффективно передается по ссылке, поскольку вы можете изменить его состояние в функции-члене.

Следуя замечанию Konrad: обратите внимание, что сам this не передается по ссылке, this является ссылкой (указателем) на объект, а передается по значению. Вы не можете изменить адрес памяти вашего объекта как хотите;)

3 Является ли массив единственным, который передается по ссылке в C ++?

Это не так. Вы увидите изменения в элементах массива, но сам массив (структура) не изменится.

После замечания FredOverflow, иллюстрация:

void fun(int* p, size_t size);

int main(int argc, char* argv[])
{
  int array[15];
  fun(array, 15);
}

Мы не знаем, что делает fun, он, вероятно, изменит некоторые элементы array, но каким бы ни было его действие, array останется массивом из 15 целых чисел: содержимое изменяется, а структура - нет.

В результате для изменения array нам понадобится еще одно объявление:

void changer(int*& array, size_t& size);

Таким образом, мы можем изменить как содержимое, так и структуру (а также передать новый размер). И, конечно же, мы можем вызывать эту функцию только с массивом, который был размещен динамически.

4 Почему я не могу использовать Foo fInstance в классе Foo?

Потому что это бесконечная рекурсия. Подумайте об этом с точки зрения компилятора и попробуйте угадать размер Foo. Размер Foo - это сумма размеров его атрибутов, плюс, возможно, некоторая информация о заполнении и типе. Кроме того, размер объекта должен быть не менее 1, чтобы его можно было адресовать. Итак, если у Foo есть Foo, каков его размер :)?

Обычное решение - использовать умный указатель:

class Foo
{
public:

private:
  std::unique_ptr<Foo> mInstance;
};

Поскольку размер указателя не зависит от размера объекта, на который указывает, поэтому здесь не происходит рекурсия :)

person Matthieu M.    schedule 26.06.2010
comment
Вы увидите изменения в элементах массива, но сам массив (структура) не изменится. - ›Я не понимаю, что вы имеете в виду, поясните, пожалуйста. - person fredoverflow; 26.06.2010
comment
Очень хороший ответ. Единственная проблема, с которой я столкнулся, касается указателя this: действительно ли он передается по ссылке? Я так не думаю - я думаю, что это принято по ценности. Конечно, изменение незаконно, даже с использованием const_cast, и компилятор интерпретирует это как rvalue. - person Konrad Rudolph; 26.06.2010
comment
@Konrad: Нет смысла даже говорить об изменении this через const_cast, потому что this - это не const для начала :) this - это указатель, указатели - это скалярные типы, а скалярные типы не имеют постоянных r-значений. - person fredoverflow; 26.06.2010
comment
@Konrad: передача указателя на объект - это способ передать объект по ссылке. - person bk1e; 26.06.2010
comment
@ bk1e: Вы могли сказать, что *this передается по ссылке, но this (без оператора разыменования) определенно не передается по ссылке. - person fredoverflow; 26.06.2010
comment
@Fred: ну, this, вероятно, можно было бы объявить как class_type* const (вполне разумное заявление, и на самом деле многие хорошие книги по C ++ побуждают читателя думать о this, как объявлено таким образом), и в этом случае const_cast будет помощь. - person Konrad Rudolph; 26.06.2010
comment
@ bk1e: Да, конечно, но «ссылка» имеет очень четкое фиксированное значение в C ++, а указатели и ссылки - это не одно и то же, и ни одна из них не передает указатель (по значению) и не передает ссылка. - person Konrad Rudolph; 26.06.2010
comment
@Konrad: Стандарт с вами не согласен. Раздел 9.3.2 четко определяет this как prvalue, и не существует такой вещи, как const prvalue, поэтому нет константы, которую можно было бы отбросить. По вашей логике также должна быть возможность отбросить константу от нулевого указателя. - person fredoverflow; 26.06.2010
comment
@Fred: Хм, а что за цена? Я не мог найти на него ссылки. Но в §9.3.2 сказано, что this имеет тип T* в неконстантной функции-члене и не является lvalue (и, следовательно, rvalue, поскольку §3.10 говорит, что «каждое выражение является либо lvalue, либо rvalue»), так что . ;-) - person Konrad Rudolph; 26.06.2010
comment
@Konrad: Извините, я цитировал C ++ 0x FCD. Prvalue C ++ 0x - это rvalue C ++ 98. - person fredoverflow; 26.06.2010
comment
@Konrad, @Fred: Я обновил свой ответ после ваших замечаний, спасибо. Я не буду вдаваться в дебаты о статусе this, однако я никогда не был большим приверженцем стандартов. - person Matthieu M.; 26.06.2010
comment
@Matthieu M .: Я думаю, вы имели в виду fun(array, 15);? - person Lazer; 27.06.2010
comment
По умолчанию массив в C ++ передается по ссылке .. void funct (int x [], int x_size) {for (int i = 0; i ‹x_size; i ++) {x [i] + = 1; }} int main () {int n [5] = {1,2,3,4,5}; int n_size = 5; функция (n, n_size); для (int i = 0; i ‹n_size; i ++) {cout ‹---------------- n [i]; } return 0; } - person Michael Sync; 28.06.2010
comment
Нет, тип вырождается в указатель, и поэтому его элементы доступны по ссылке, но не сам массив. - person Matthieu M.; 28.06.2010

Поскольку здесь так много заблуждений и совершенно ложных ответов, это моя попытка исправить это:

В чем разница между void DoSomething(const Foo& foo) и void DoSomething(Foo foo)?

Как говорили другие, второй код требует копии (обычно вызывая конструктор копирования Foo).

Итак, почему использование const + & становится лучшей практикой по сравнению с аргументом без & и const?

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

С другой стороны, когда вы передаете объект как const ссылку, это внутренне (обычно) реализуется через указатель. Указатели можно всегда эффективно копировать на всех архитектурах.

В книге, которую я читаю, сказано, что функции-члены передают неявный параметр по ссылке.

Я считаю, что книга неправильная. Функции-члены классов неявно передают указатель this, который ссылается на текущий объект. Однако это указатель, и C ++ запрещает его изменять. Нет причин, по которым он будет передаваться по ссылке.

Является ли массив единственным, что передается по ссылке в C ++?

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

void foo(int[] x) { … }

на самом деле то же самое, что и

void foo(int* x) { … }

Компилятор считает эти два объявления одинаковыми. Когда вы пытаетесь вызвать любой из этих методов и передать ему массив x, C ++ неявно преобразует массив в указатель на его первый элемент - это называется «распад». Итак, foo(x) станет foo(&x[0]).

Однако массивы можно вместо этого передавать по ссылке, если указан их размер:

void foo(int (&x)[4]);

Но опять же, вы явно объявляете, что массив передается по ссылке.

person Konrad Rudolph    schedule 26.06.2010
comment
void foo(int x[4]) в точности совпадает с void foo(int x[]) и void foo(int *x). Размер просто игнорируется. Массивы никогда не передаются неявно по ссылке. Вы должны изменить эту последнюю часть на void foo(int (&x)[4]). - person fredoverflow; 26.06.2010
comment
Мне сейчас нравится твой ответ :) +1 от меня. - person fredoverflow; 26.06.2010
comment
отлично .. большое спасибо за ответ .. теперь у меня есть четкое понимание ... большое спасибо .. - person Michael Sync; 27.06.2010

В C # объект передается «по ссылке», но, похоже, этого нет в C ++.

Нет, это неправильно, это распространенное заблуждение. В таких языках, как C #, VB и Java, переменные всегда передаются по значению (исключение явно передается как ref в C # или ByRef в VB).

Отличие от C ++ в том, что переменные не содержат самого объекта класса, они содержат только ссылку. Таким образом, методу передается не сам объект, а только его ссылка (но это передается по значению).

Разница весьма существенная. Если C # использовал передачу по ссылке, следующий код распечатал бы другой результат:

void foo(string s) {
    s = "world";
}

string s = "hello";
foo(s);
Console.WriteLine(s); // prints "hello"
person Konrad Rudolph    schedule 26.06.2010
comment
›› явно передается как ссылка в C # или ByRef в VB) Я так не думаю. В C # по умолчанию используется ссылка при передаче объекта ... - person Michael Sync; 26.06.2010
comment
Извините .. Я должен был упомянуть, что передача объекта в C # осуществляется по ссылке (а не по строке, int и т. Д.). - person Michael Sync; 26.06.2010
comment
@Michael: В C # по умолчанию при передаче объекта используется ссылка по умолчанию - ›Нет, просто ссылка передается по значению. Это отличается от передачи по ссылке, которой можно добиться с помощью ключевого слова ref в C #. - person fredoverflow; 26.06.2010
comment
@Michael: string - это нормальный класс в C #, ничего особенного. Вы можете протестировать этот пример с любым другим классом вместо string и получить такое же поведение. - person Konrad Rudolph; 26.06.2010

Почему я не могу использовать Foo fInstance в классе Foo?

Потому что концептуально объекту Foo потребуется бесконечное количество места. Технически тип Foo неполон в определении Foo.

Что вам, вероятно, нужно, так это указатель на Foo как на член.

person fredoverflow    schedule 26.06.2010

Разница между void DoSomething(const Foo& foo) и void DoSomething(Foo foo) заключается в том, что первый передает параметр по ссылке, а второй - по значению. Практические отличия заключаются в следующем:

  1. Эффективность. Передача по значению может потребовать вызова конструктора копирования. Если конструктор копирования стоит дорого, передача по значению приведет к дополнительным накладным расходам.
  2. Применимость. Для передачи по значению требуется общедоступный конструктор копии. Если класс не поддерживает конструктор копирования, его нельзя передать по значению.
  3. Семантика. При передаче по ссылке вы не знаете, на кого можно ссылаться. Если базовый объект изменяется по какой-либо другой причине, значение ссылки изменится.

Чтобы объяснить №3 немного лучше, рассмотрим следующую ситуацию:

std::string global_string;

void foo(const std::string &str)
{
    if (str.empty())
    {
        global_string = "whatever";
        // is str still empty??
    }
}

Если foo вызывается как foo(global_string), то при изменении global_string это также изменяетstr.

person R Samuel Klatchko    schedule 26.06.2010
comment
да. он передается по ссылке, но мы помещаем туда const, так что он все равно не будет изменен, верно? Почему лучше писать (const Person & p) вместо просто (Person p) ?? спасибо за ответ 3 .. - person Michael Sync; 26.06.2010
comment
@MichaelSync - передача по константной ссылке лучше, потому что она более эффективна и будет работать, даже если тип не может быть скопирован (т.е. мои №1 и №2). const говорит, что функция не будет изменять объект, но не распространяется на случай его изменения каким-либо другим методом. - person R Samuel Klatchko; 26.06.2010
comment
Спасибо. Я добавил еще один вопрос в свой пост. Не могли бы вы ответить и на это? Спасибо. - person Michael Sync; 26.06.2010
comment
Но в вашем примере функция может измениться str из-за псевдонима с global_string :) - person fredoverflow; 26.06.2010
comment
Это не очень хорошая практика. См. cpp-next.com/archive/2009/ 08 / хочу-скорость-передать-по-значению. В любом случае, одной из причин const& может быть то, что объект нельзя скопировать. (Если вы отметите конструктор копирования как частный). - person jalf; 26.06.2010
comment
Я бы добавил, что передача по ссылке позволяет передавать объекты производного типа ... что весьма полезно! - person Matthieu M.; 26.06.2010
comment
@Mat: передача по значению также позволяет передавать объекты производного типа, просто семантика, которую вы получаете (нарезка объектов), вероятно, не то, что вам нужно;) - person fredoverflow; 26.06.2010

Один за раз:

  1. doStuff(Foo f) означает, что новый Foo объект будет создан в стеке при вызове метода - AKA по значению. Вызов doStuff(const Foo &f) означает, что вы просто передаете новую ссылку, объект не дублируется, вы только держите ссылку на него. Это самый безопасный способ передачи аргументов, поскольку он не требует дублирования копии объекта. Это называется передачей по ссылке и является наиболее близким к поведению Java / C #.

  2. О каком неявном параметре вы говорите?

  3. Опять же, массивы (при условии, что они std::arrays) могут передаваться по значению, указателю или ссылке - единого поведения нет. Как упоминал Конард, массивы в стиле C (не более чем блоки памяти) не могут передаваться по значению.

person Yuval Adam    schedule 26.06.2010
comment
Спасибо. да. но поскольку мы помещаем const в первый, этот объект нельзя изменить, поэтому он будет таким же, как Person p. Я не уверен, почему рекомендуется использовать const Person & p вместо Person p, если он такой же вещь? - person Michael Sync; 26.06.2010
comment
Это не означает, что объект нельзя изменить, это означает, что ссылку нельзя изменить. - person Yuval Adam; 26.06.2010
comment
@ Юваль Что? Ссылки всегда неявно постоянны. const T& x означает, что x является ссылкой на объект T, и компилятор проверяет, не изменяете ли вы этот T объект посредством ссылки x. - person fredoverflow; 26.06.2010
comment
Массивы нельзя передавать по значению в C ++. - person Konrad Rudolph; 26.06.2010
comment
@Konrad: массивы в стиле C не могут, но std::array может;) - person fredoverflow; 26.06.2010
comment
@Fred: std::vector тоже - это любой другой класс. ;-) Но я думаю, что имел в виду старый добрый массив в стиле C. - person Konrad Rudolph; 26.06.2010
comment
@Konrad: Совершенно верно, отсюда и мой смайлик;) - person fredoverflow; 26.06.2010

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

В этом сообщении блога объясняется, почему.

Люди склонны думать, что ссылка на константу выполняется быстрее, но правда в том, что компилятору разрешено оптимизировать копию при передаче по значению, поэтому передача по значению является хорошим вариантом по умолчанию (и действительно, стандартная библиотека обычно это делает. Например, , std::for_each принимает два итератора по значению и один функтор по значению)

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

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

Другой причиной передачи по ссылке (константной или иной) может быть использование полиморфных объектов. Допустим, у вас есть базовый класс B и производный класс D. Вы можете безопасно передать объект типа D как const B&, но передача его по значению в качестве объекта типа B может привести к разрезанию (копируется только подобъект B, а не весь объект D).

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

person jalf    schedule 26.06.2010
comment
@jalf: раскрасьте меня скептически. Стандартная библиотека передает итераторы и функциональные объекты только по значению, исходя из предположения, что эти объекты обычно небольшие. Если компиляторы действительно могут оптимизировать передачу по значению, то это, конечно, верно только в последних компиляторах, и то только в особых обстоятельствах. Я совершенно не уверен, что даже современные компиляторы исключают копии для аргументов (в отличие от возвращаемых значений). Сообщение в блоге, на которое вы ссылаетесь, также не поддерживает вас: в нем говорится только о NRVO (т.е. возвращаемых значениях) и передаче по значению в тех местах, где в любом случае предназначена копия. - person Konrad Rudolph; 26.06.2010
comment
И последнее, но не менее важное: если бы то, что вы сказали, было правдой, ссылки на rvalue были бы практически избыточными. На самом деле они были введены в язык именно для устранения этих недостатков. - person Konrad Rudolph; 26.06.2010
comment
@jalf: Я не согласен. Итераторы особенные, они разработаны для передачи по значению, как и функциональные объекты. Если вы посмотрите на Эффективный C ++, книга предлагает передавать примитивы, итераторы и функторы по значению, а почти все остальное - по ссылке на const. Статья, которую вы связали, применима только к C ++ 0x. Без семантики перемещения передавать все по значению - плохой совет, imho. - person fredoverflow; 26.06.2010
comment
@Konrad: современные компиляторы очень хорошо умеют копировать. Правда, в старых компиляторах он менее надежен, но сегодня это довольно безопасный вариант. И сообщение в блоге указывает, что передача по значению может быть быстрее в тех случаях, когда копия предназначена в любом случае, но также, что в любом случае она обычно не медленнее. Конечно, нет никакой гарантии, что каждая копия будет удалена, но это очень часто бывает, если вы посмотрите на вывод компилятора. :) Не стесняйтесь доказывать, что я ошибаюсь. Попробуйте, и проверьте разборку. - person jalf; 26.06.2010
comment
@Konrad: Нет, ссылки rvalue были введены еще по нескольким причинам. Безупречная переадресация - один из примеров. Семантика перемещения также не может быть реализована полностью и надежно без ссылок rvalue. Copy elision дает вам лишь часть пути (и зависит от компилятора для оптимизации) - person jalf; 26.06.2010
comment
@jalf: вам не нужна семантика перемещения, если вы можете исключать копии. Все, что вам нужно, это swap. - person Konrad Rudolph; 26.06.2010

  What is the differences between void DoSomething(const Foo& foo) and

void DoSomething (Foo foo)?

прагматически нет никакой разницы, константа не позволит вам изменить содержимое 'foo', тогда как передача по значению также не повлияет на содержимое аргумента, однако с точки зрения эффективности const Foo & foo более эффективна, поскольку она не будет создать копию при передаче объекта методу.

person AndersK    schedule 26.06.2010

В книге, которую я читаю, сказано, что функции-члены передают неявный параметр по ссылке.

В книге говорится о неявном указателе this, который передается каждой нестатической функции-члену, определенной в классе. Это потому, что C ++ хранит копию каждой функции-члена в классе не в каждом объекте, поэтому метод должен знать, с каким объектом этого класса он должен работать.

class FOO{
 int x;
 void doSomthing(int x);
}

void FOO::doSomething(int x){
  x = x;
}

будет скомпилирован во что-то вроде этого

void FOO::doSomething(FOO* this, int x){
  this->x = x;
}

Поскольку статические функции являются функциями класса, а не функциями объекта, им не нужно создавать объект для вызова, поэтому они не должны иметь доступа к нестатическим полям класса и, следовательно, не нуждаются в this указатель на объект.

person LmSNe    schedule 26.06.2010
comment
this->, и ваш пример кажется неправильным, он должен компилироваться в this->x = this->x, что совершенно бесполезно. Этот трюк работает только в списке инициализаторов. - person Matthieu M.; 26.06.2010
comment
@Mathieu: нет, x относится к локальной переменной (параметр - внутренняя область скрывает внешнюю область), а this->x относится к члену. - person Konrad Rudolph; 26.06.2010
comment
@Matthieu: то, что сказал Конард, я имел в виду. Но Вы правы насчет оператора - ›, а не оператора. оператор. моя ошибка :) - person LmSNe; 26.06.2010

В чем разница между void DoSomething (const Foo & foo) и void DoSomething (Foo foo)?

Вообще говоря, последний будет глубоко скопировать передаваемый аргумент (другими словами, он сделает копию исходного объекта Foo). Первый сделает неглубокую копию переданного аргумента (копируя его адрес в неизменяемую константную ссылку, а не копируя фактический объект Foo).

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

Может ли кто-нибудь дать мне образец неявного параметра и по ссылке? Я знаю, что если мы хотим передать объект по ссылке, нам нужно использовать & (например, Foo (Person & p)), но почему С ++ передает объект по ссылке для неявного параметра? Я читал, что неявный параметр в C ++ похож на Contructor (string str): strMemberVariable (str) {} ...

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

class Foo
{
    Foo(int x) {...}
};

Это неявно. Это позволяет нам писать такой код:

Foo foo = 123;

void f(const Foo& x);
f(123);

Хотя это явно:

class Foo
{
    explicit Foo(int x) {...}
};

... а не предыдущий код. Соответствующим образом необходимо изменить предыдущий код:

Foo foo(123);

void f(const Foo& x);
f(Foo(123) );

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

Является ли массив единственным, что передается по ссылке в C ++?

Я не совсем уверен, о чем здесь спрашивают, но массивы нельзя передавать по значению, если вы это имеете в виду. Мы можем передавать только ссылки / указатели на массивы:

// takes an array of 10 integers
void fn(int(&some_array)[10]);

// takes a pointer to an int array
void fn(int* some_array);

// takes a pointer to an int array (the 10 
// literal constant is ignored) and this function
// can likewise take any pointer to int
void fn(int some_array[10]);

Почему я не могу использовать Foo fInstance в классе Foo?

Это бесконечно рекурсивно. Foo хранит fInstance, fInstance хранит другой fInstance и так далее. Нет ничего, что могло бы остановить рекурсию, поэтому у вас были бы просто объекты, хранящие объекты, хранящие объекты, хранящие объекты, и так далее, пока у вас не закончится память. Таким образом, компиляторы обнаруживают это условие и запрещают его, поскольку из него не может возникнуть законное поведение во время выполнения. Также не было бы способа определить размер Foo - это было бы бесконечное значение.

person stinky472    schedule 27.06.2010

void DoSomething(Foo foo)

Фактически передает копию foo и

void DoSomething(Foo& foo)

Передает ссылку на foo, поэтому, если вы измените foo в своей функции, вы измените исходный foo. Я надеюсь в этом есть смысл.

Что касается массивов, массив на самом деле является указателем на начало массива, и этот указатель передается (весь массив не копируется).

array[5] = 0;//is the same as :
*(array+5) = 0; //this
person fingerprint211b    schedule 26.06.2010
comment
Последние две строки в вашем ответе неверны. Вы предполагаете sizeof(array[0])==1 - person Yuval Adam; 26.06.2010
comment
Не совсем, указатель имеет тип и будет увеличиваться на sizeof (that_type). (Если я правильно понял, что вы хотели сказать) - person fingerprint211b; 26.06.2010
comment
@YuvalA - вы не правы. arr[x] и *(arr + x) семантически эквивалентны в C ++. Арифметика указателя учитывает тип указателя и действует правильно. - person R Samuel Klatchko; 26.06.2010
comment
В C ++ нет абсолютно никакой возможности передавать ссылки по значению. - person fredoverflow; 26.06.2010
comment
В книге рекомендуется использовать const Person & p вместо Person p, даже если это одно и то же .. Есть ли у вас какие-либо комментарии по этому поводу? - person Michael Sync; 26.06.2010
comment
Вы не можете копировать ссылки в C ++, потому что они не являются объектами. Ссылки были специально введены в C ++ для поддержки передачи по ссылке. - person fredoverflow; 26.06.2010
comment
Передает постоянную ссылку на foo, поэтому, если вы измените foo в своей функции - ›Но вы не сможете изменить foo! Вы явно помечаете const не ссылку, а вид объекта. Ссылки всегда неявно постоянны. В C ++ нет такой вещи, как изменяемая ссылка. - person fredoverflow; 26.06.2010
comment
Правильно, я имел в виду это как общий случай для ссылок / указателей, а не для константных ссылок. И снова исправлено. - person fingerprint211b; 26.06.2010

В чем разница между void DoSomething (const Foo & foo) и void DoSomething (Foo foo)

DoSomething (Foo foo) передает объект foo по значению, если Foo является примитивным типом данных, но по ссылке, если Foo является пользовательским типом данных. Но во втором случае, если вы измените foo, он отразится обратно на исходный объект, что часто нежелательно. Об этом позаботится DoSomething (const Foo & foo), который передает foo по ссылке (таким образом, экономя дополнительные затраты памяти на передачу по значению) и по-прежнему не предоставляет доступ на запись в foo функции DoSomething. Таким образом, это лучшая практика.

Может ли кто-нибудь дать мне образец неявного параметра и по ссылке?

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

Является ли массив единственным, что передается по ссылке в C ++?

Нет, все определенные пользователем объекты передаются по ссылке.

person Prashant    schedule 26.06.2010
comment
Ладно. это - ›переменная-член означает неявный параметр, не так ли? Теперь мне ясно. Спасибо. - person Michael Sync; 26.06.2010
comment
все определенные пользователем объекты передаются по ссылке - ›Совершенно неверно. Вы путаете C ++ с C # или Java? - person fredoverflow; 26.06.2010