это понятнее и эффективнее, чем перечисление :
from nltk.corpus import wordnet
def get_wordnet_pos(self, treebank_tag):
if treebank_tag.startswith('J'):
return wordnet.ADJ
elif treebank_tag.startswith('V'):
return wordnet.VERB
elif treebank_tag.startswith('N'):
return wordnet.NOUN
elif treebank_tag.startswith('R'):
return wordnet.ADV
else:
return ''
def penn_to_wn(tag):
return get_wordnet_pos(tag)
Встроенные типы и небольшие объекты (такие как итераторы STL) обычно должны передаваться по значению.
Это отчасти предназначено для расширения возможностей компилятора по оптимизации. Компилятору на удивление сложно узнать, является ли ссылочный параметр псевдонимом другого параметра или глобального - ему, возможно, придется перечитывать состояние объекта из памяти несколько раз через функцию, чтобы убедиться, что значение не изменилось.
Это причина ключевого слова restrict
в C99 (та же проблема, но с указателями).
Если переданный объект является интеллектуальным указателем (т.е. собственный подсчет ссылок), тогда передача по значению может быть более разумной.
Я понимаю, что это своего рода боковой ответ на ваш вопрос - объект, заключенный в интеллектуальный указатель, не копируется при передаче по значению, поэтому он больше похож на передачу по ссылка в таком случае. Тем не менее, семантика «по ссылке» в этом случае не нужна.
Однако есть проблема с моей логикой рассуждений - вы потеряете «постоянство» аргумента, передавая его по значению. Возможно, вам все-таки стоит использовать семантику "по ссылке" ...
Если вы хотите локально изменить t
(не затрагивая оригинал) в теле вашего метода (скажем, в процессе вычисления чего-либо), первым методом будет льготный.
Не забывайте, что есть случаи, когда есть разница - когда вы имеете дело с объектами со странной семантикой копирования / присваивания.
auto_ptr <>
- классический пример - передайте те вокруг по цене, не думая о последствиях, и вы можете закончить беспорядок.
Кроме того, foo (T t) обычно используется, когда T является простым типом (int, bool и т. Д.).
Another case that hasn't been mentioned is heavy use of the object. Let's say you pass a struct with 5 ints as members. If you are going to be accessing all 5 quite a lot in your function, there comes a point when the dereference cost outweighs the copy cost. However, you'd have to run a profiler to know when that is.
I should point out, though, that things like STL containers, which allocate memory on the heap, should almost never be passed by value if avoidable, because heap allocation is very slow compared to stack allocation.
Это случай, когда у вас нет другой возможности, а только передать параметр по значению. Конечно, Boost справляется с этим. Но без усиления мы должны передать Value для работы по значению.
class Test
{
public:
Test()
{
std::set<std::string> values;
values.insert("A");
values.insert("V");
values.insert("C");
std::for_each(values.begin(), values.end(),
bind1st(mem_fun(&Test::process), this));
}
private:
void process( std::string value )
{
std::cout << "process " << value << std::endl;
}
};
Причина, по которой передача по константной ссылке и по значению концептуально одинакова, заключается в том, что ни один из них не может изменить оригинал.
Обычно я большой поклонник передачи по значению, потому что он создает код, который позволяет избежать многих сложностей, которые возникают, когда несколько потоков совместно используют доступ к общим данным.
Тем не менее, это потенциально может замедлить ваш код . В прошлом я всегда отдавал предпочтение передаче по значению, если только я не знаю, что это (или будет) проблема производительности при этом. Возможно, мне придется немного изменить это, чтобы включить передачу по константной ссылке как еще лучший вариант.
Если наиболее простая реализация функции включает локальное изменение значения параметра, то имеет смысл передавать его по значению, а не по константной ссылке
Например, однострочная версия strcpy:
char *strcpy(char *dest, const char *src)
{
while (*dest++ = *src++);
return s1;
}
Если вы использовали указатели как константные ссылки, вам нужно было бы скопировать их во временные библиотеки в теле вашей программы, а не позволять механизму передачи параметров делать это за вас.
Некоторым подпрограммам требуется копия, поэтому их нельзя передавать по ссылке. Например, генератору ходов шахматной программы может потребоваться копия текущей позиции для работы (рекурсивно) вместо фактического изменения исходного экземпляра позиции.
Boost.CallTraits - менее известное, но полезное средство для передачи параметров и результатов с помощью наиболее эффективного метода, доступного для рассматриваемого типа.
Answered in this answer. This is a SymLink to that answer. Please vote there, if anywhere :)
Два очень специфических случая:
Когда вы пишете операторы присваивания с строгими гарантиями исключений, вы можете либо записать их как
X& X::operator=(const X& orig)
{
X tmp(orig);
swap(this, tmp);
return *this;
}
, либо признать, что первое, что произойдет, это то, что вы сделайте копию и сделайте это как часть вызова
X& X::operator=(X tmp)
{
swap(this, tmp);
return *this;
}
. Если у вас есть интеллектуальный указатель с семантикой владения, например auto_ptr
, и вы хотите передать право владения вызываемой функции, вы должны передать его стоимость. Конечно, 8 человек сейчас быстро укажут, что вы, вероятно, не хотите использовать auto_ptr
, и они, вероятно, правы, но иногда вы не делаете этот выбор.
Хотя это совсем не конкретно. , Я часто заканчиваю тем, что передаю небольшие объекты по значению, когда это экономит мне выделение памяти в куче. Мало того, что фактическое выделение и окончательное освобождение занимает время, но и ссылка на все через указатель ничего не делает для улучшения локальности ваших данных. Другими словами, это может повлиять на вашу производительность. Где именно находится точка безубыточности, будет зависеть от вашего приложения, но я лично без колебаний передам объект, размер которого составляет несколько размеров указателя.
Они вообще концептуально не равны ...
Первый создает копию объекта внутри функции. Это означает, что значение можно безопасно изменить в функции. Это также означает, что произошла полная копия объекта, что может быть проблемой, если объект большой.
Последний создает псевдоним для объекта и заявляет, что его нельзя изменить внутри объекта. Копирование не происходит, но каждый доступ к объекту внутри функции требует разыменования. Компилятор позаботится об этом за нас, но это все еще важно знать.
Разница становится очень важной, если у вас есть тип, который обычно передается в регистрах. Например, целые числа, числа с плавающей запятой и даже векторы с плавающей запятой на некоторых платформах. Проблемы производительности диктуют, что вы хотите запретить оставаться в регистре как можно дольше, не записывая себя обратно в память, а передача по значению делает это гораздо более вероятным.
Так что для базовых типов (char, short, int, long , float, double), вы всегда должны отдавать предпочтение передаче по значению , если только вам не нужно специально использовать ссылку для сохранения значения для использования после выхода из функции. Для полных объектов обычно предпочитают передавать по константной ссылке.