Где я должен предпочесть передачу по ссылке или пропускную стоимость?
В каких обстоятельствах я предпочитаю передачу по ссылке? Передача по значению?
Ответы
Ответ 1
Существует пять основных случаев, когда вы должны использовать pass-by-reference через pass-by-value:
- Если вы вызываете функцию, которую нужно изменить свои аргументы, использование пройти по ссылке, как его единственный способ, чтобы получить этот эффект (я лечения пройти по ссылке и передача по указателю взаимозаменяемо в данном случае, хотя с пошаговым указателем вам часто приходится явно проверять NULL).
- Если вы вызываете функцию, которая должна принимать большой объект в качестве параметра, передайте его с помощью ссылки const, чтобы избежать необходимости делать ненужную копию этого объекта и сильно ударить по эффективности.
- Если вы пишете конструктор копирования, который по определению должен взять ссылку, используйте pass by reference.
- Если вы пишете функцию, которая хочет работать в полиморфном классе, используйте pass by reference или передайте указатель, чтобы избежать нарезки.
- Если вы пишете функцию, которая может возвращать очень большой или непокрываемый объект, используйте pass by reference как способ использования параметра для хранения полученного значения.
Ответ 2
Существует несколько соображений, в том числе:
Производительность
Передача по значению копирует данные, поэтому передача больших структур данных по значению может препятствовать производительности. Передача по ссылке пропускает только данные (в основном адрес) к данным. Для больших структур данных это может значительно повысить производительность. Для небольших структур данных (например, int) передача по ссылке может препятствовать работе.
Модификации
Передача по значению копирует данные, поэтому, если целевой код изменяет эту копию, это не повлияет на оригинал. Передача по ссылке пропускает только адрес данных, поэтому модификации, сделанные против этой ссылки, будут "видимыми" для вызывающего кода.
Ответ 3
Да.
Переходите по значению для таких вещей, как родные типы, которые достаточно малы, чтобы их передача напрямую была эффективной. В противном случае используйте pass (const
) ссылку.
В жесткой части написана шаблон, который может применяться к любому (в этом случае вы обычно хотите использовать pass by reference - потенциальный штраф за прохождение большого объекта по стоимости намного хуже, чем потенциальный штраф за прохождение по ссылка при прохождении по значению была бы предпочтительной).
Изменить: это, конечно, предполагает ситуацию, когда требуемая семантика позволяла бы либо одно - очевидно, если вы работаете с чем-то вроде полиморфных объектов, нет никакого реального "предпочтения", потому что вы должны использовать указатель или ссылку для получения правильного поведения.
Ответ 4
Поскольку другие уже достаточно хорошо ответили на ваш вопрос, я хотел бы добавить важный момент:
Если класс не имеет public
copy-constructor, то у вас нет выбора для передачи по значению; вы должны проходить по ссылке (или вы можете передать указатель).
Следующая программа не будет компилироваться:
class A
{
public:
A(){}
private:
A(const A&) {}
};
//source of error : pass by value
void f(A ) {}
int main() {
A a;
f(a);
return 0;
}
Ошибка:
prog.cpp: В функции 'int main():
prog.cpp: 10: ошибка: "A:: A (const A &) является приватным
prog.cpp: 18: ошибка: в этом контексте
prog.cpp: 18: ошибка: инициализация аргумента 1 из 'void f (A)
Посмотрите на идеон: http://www.ideone.com/b2WLi
Но как только вы сделаете функцию f
пройденной по ссылке, тогда она компилируется отлично: http://www.ideone.com/i6XXB
Ответ 5
Вы отметили свой вопрос как с C, так и с С++.
Поэтому я предлагаю вам рассмотреть возможность использования pass by reference в С++, который поддерживает эту функцию, и что вы не рассматриваете ее использование в C, которая не поддерживает эту функцию.
Ответ 6
В то время как указатели являются ссылками, "ссылка" в С++ обычно относится к практике пометки параметра SomeType &.
Что вы никогда не должны делать. Единственное место, которое оно подходит, - это волшебный синтаксис, необходимый для реализации различных предопределенных операторов. В противном случае:
-
Вы никогда не должны передавать параметры по ссылке - переходите по указателю, иначе вы делаете обзоры кода практически невозможными. Передача по ссылке делает невозможным рассказать, просмотрев вызов, параметры которого можно ожидать изменить.
-
Вы также не должны передавать параметр по ссылке. Опять же, это означает, что вы выполняете мета-оптимизацию. Вы всегда должны просто передавать по значению, в противном случае вы виновны в том, чтобы заглянуть внутрь объекта, изучив его реализацию и решив, что по какой-либо причине предпочтение отдается предпочтению.
Любой класс С++ должен реализовать все конструкторы копирования и присваивания и перегрузки, необходимые для передачи по значению. В противном случае он не выполнил свою работу, отвлекая программиста от деталей реализации класса.