есть ли какой-либо конкретный случай, где передача значением предпочтена по pass-by-const-reference в C++?

это понятнее и эффективнее, чем перечисление :

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)
6
задан t.g. 23 May 2009 в 01:36
поделиться

15 ответов

Встроенные типы и небольшие объекты (такие как итераторы STL) обычно должны передаваться по значению.

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

Это причина ключевого слова restrict в C99 (та же проблема, но с указателями).

10
ответ дан 8 December 2019 в 04:10
поделиться

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

Я понимаю, что это своего рода боковой ответ на ваш вопрос - объект, заключенный в интеллектуальный указатель, не копируется при передаче по значению, поэтому он больше похож на передачу по ссылка в таком случае. Тем не менее, семантика «по ссылке» в этом случае не нужна.

Однако есть проблема с моей логикой рассуждений - вы потеряете «постоянство» аргумента, передавая его по значению. Возможно, вам все-таки стоит использовать семантику "по ссылке" ...

2
ответ дан 8 December 2019 в 04:10
поделиться

Если вы хотите локально изменить t (не затрагивая оригинал) в теле вашего метода (скажем, в процессе вычисления чего-либо), первым методом будет льготный.

5
ответ дан 8 December 2019 в 04:10
поделиться

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

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

2
ответ дан 8 December 2019 в 04:10
поделиться

Кроме того, foo (T t) обычно используется, когда T является простым типом (int, bool и т. Д.).

1
ответ дан 8 December 2019 в 04:10
поделиться

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.

1
ответ дан 8 December 2019 в 04:10
поделиться

Это случай, когда у вас нет другой возможности, а только передать параметр по значению. Конечно, 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;
    }
};
1
ответ дан 8 December 2019 в 04:10
поделиться

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

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

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

1
ответ дан 8 December 2019 в 04:10
поделиться

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

Например, однострочная версия strcpy:

char *strcpy(char *dest, const char *src)
{
   while (*dest++ = *src++);

   return s1;
}

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

1
ответ дан 8 December 2019 в 04:10
поделиться
  1. Как отмечалось ранее, предпочитайте передачу по значению, если вам нужна копия объекта в своей функции.
  2. Я обычно использую передачу по значению, если копирование T дешевле, чем создание / копирование ссылки, например, T = char, T = short. Преимущество здесь может зависеть от платформы, и вы, вероятно, все равно захотите, чтобы const там, где это применимо, помогала оптимизатору.
0
ответ дан 8 December 2019 в 04:10
поделиться

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

0
ответ дан 8 December 2019 в 04:10
поделиться

Boost.CallTraits - менее известное, но полезное средство для передачи параметров и результатов с помощью наиболее эффективного метода, доступного для рассматриваемого типа.

0
ответ дан 8 December 2019 в 04:10
поделиться

Answered in this answer. This is a SymLink to that answer. Please vote there, if anywhere :)

0
ответ дан 8 December 2019 в 04:10
поделиться

Два очень специфических случая:

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

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 , и они, вероятно, правы, но иногда вы не делаете этот выбор.

Хотя это совсем не конкретно. , Я часто заканчиваю тем, что передаю небольшие объекты по значению, когда это экономит мне выделение памяти в куче. Мало того, что фактическое выделение и окончательное освобождение занимает время, но и ссылка на все через указатель ничего не делает для улучшения локальности ваших данных. Другими словами, это может повлиять на вашу производительность. Где именно находится точка безубыточности, будет зависеть от вашего приложения, но я лично без колебаний передам объект, размер которого составляет несколько размеров указателя.

1
ответ дан 8 December 2019 в 04:10
поделиться

Они вообще концептуально не равны ...

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

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

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

Так что для базовых типов (char, short, int, long , float, double), вы всегда должны отдавать предпочтение передаче по значению , если только вам не нужно специально использовать ссылку для сохранения значения для использования после выхода из функции. Для полных объектов обычно предпочитают передавать по константной ссылке.

1
ответ дан 8 December 2019 в 04:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: