“константа T &arg” по сравнению с “T аргумент”

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

17
задан Don 8 August 2018 в 19:16
поделиться

14 ответов

Используйте const T & arg , если sizeof (T)> sizeof (void *) , и используйте T arg if sizeof (T) <= sizeof (void *)

38
ответ дан 30 November 2019 в 09:58
поделиться

Они делают разные вещи. const T & заставляет функцию использовать ссылку на переменную. С другой стороны, T arg вызовет конструктор копирования объекта и передаст копию . Если конструктор копирования недоступен (например, он частный ), аргумент не будет работать:

class Demo {
    public: Demo() {} 
    private: Demo(const Demo& t) { } 
};

void foo(Demo t) { }

int main() {
    Demo t;
    foo(t); // error: cannot copy `t`.
    return 0;
}

Для небольших значений таких как примитивные типы (где все имеет значение содержимое объекта, а не реальная ссылочная идентичность; скажем, это не дескриптор или что-то в этом роде), T arg обычно предпочтительнее. Для больших объектов и объектов, которые нельзя скопировать и / или сохранить ссылочную идентичность, важно (независимо от размера), передача ссылки предпочтительна.

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

20
ответ дан 30 November 2019 в 09:58
поделиться

Взято из Конструкторы перемещения . Мне нравятся простые правила

  1. . Если функция намеревается изменить аргумент в качестве побочного эффекта, воспользуйтесь ссылкой / указателем на неконстантный объект. Пример:

     void Transmogrify (Widget & toChange);
    void Increment (int * pToBump);
    
  2. Если функция не изменяет свой аргумент, а аргумент имеет примитивный тип, принимайте его по значению. Пример:

     double Cube (двойное значение);
    
  3. В противном случае

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

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

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

В вашем случае вы должны брать int по значению, потому что вы не собираетесь изменять аргумент, а аргумент имеет примитивный тип. Я думаю, что «примитивный тип» - это либо неклассовый тип, либо тип без определяемого пользователем конструктора копирования, и где sizeof (T) составляет всего пару байтов.

14
ответ дан 30 November 2019 в 09:58
поделиться

Ну да ... другие ответы об эффективности верны. Но здесь происходит кое-что еще, что важно - передача класса по значению создает копию и, следовательно, вызывает конструктор копии. Если вы занимаетесь там необычными вещами, это еще одна причина использовать ссылки.

2
ответ дан 30 November 2019 в 09:58
поделиться

Для простых типов, таких как int, double и char *, имеет смысл передавать его по значению. Для более сложных типов я использую const T &, если нет особой причины не делать этого.

Стоимость передачи 4-8-байтового параметра настолько мала, насколько это возможно. Вы ничего не покупаете, передавая ссылку. Для более крупных типов передача по значению может быть дорогостоящей.

1
ответ дан 30 November 2019 в 09:58
поделиться

Что ж, разница между ними на самом деле не имеет большого значения для целых чисел.

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

В обоих случаях вы видите это в вызывающем

myFunct(item);

Для вызывающего, элемент myFunct не будет изменен , но передача по ссылке не требует затрат на создание копии.

Есть очень хороший ответ на аналогичный вопрос в Передача по ссылке / значению в C ++

0
ответ дан 30 November 2019 в 09:58
поделиться

Разница между ними в том, что один передает int (который копируется), а другой использует существующий int. Поскольку это ссылка const , она не изменяется, поэтому работает почти так же. Большая разница здесь в том, что функция может изменять значение int локально, но не ссылку const . (Я полагаю, какой-то идиот мог бы сделать то же самое с const_cast <> , или, по крайней мере, попытаться сделать это.) Для более крупных объектов я могу придумать два различия.

Во-первых, некоторые объекты просто не могут быть скопированным, auto_ptr <> s и объекты, содержащие их, являются очевидным примером.

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

0
ответ дан 30 November 2019 в 09:58
поделиться

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

Для типов, определяемых пользователем (или шаблонов, если вы не знаете, что будет передаваться), предпочитайте const &. Размер ссылки, вероятно, меньше размера шрифта. И это не повлечет за собой лишнюю копию (без вызова конструктора копирования).

3
ответ дан 30 November 2019 в 09:58
поделиться

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

Редактировать: (в основном в ответ на комментарии Джеффа Харди): Это правда, что переход по ссылке const, вероятно, является «самой безопасной» альтернативой в рамках самое большое количество обстоятельств - но это не значит, что это всегда лучший выход. Но, чтобы понять, что здесь обсуждается, вам действительно нужно довольно внимательно прочитать всю статью Дэйва, так как она носит довольно технический характер, а доводы, лежащие в основе ее выводов, не всегда интуитивно очевидны (и вам нужно понимать рассуждения, чтобы делать разумный выбор. ).

5
ответ дан 30 November 2019 в 09:58
поделиться

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

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

-1
ответ дан 30 November 2019 в 09:58
поделиться

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

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

Решения, основанные на реальных физических размерах объектов, зависящих от реализации, должны как можно чаще оставлять на усмотрение компилятора. Пытаемся "портить" ваш код до этих размеров путем жесткого кодирования метода передачи является полностью контрпродуктивной тратой усилий в 99 случаях из 100. (Да, это правда, что в случае языка C ++ компилятор не имеет достаточной свободы для использования эти методы взаимозаменяемы - в общем случае они на самом деле не взаимозаменяемы в C ++. Хотя, при необходимости, правильный [полу] автоматический выбор передаваемых метио на основе размера может быть реализован посредством метапрограммирования шаблона; но это уже другая история).

Гораздо более значимый критерий для выбора метода передачи при написании кода «вручную» может звучать следующим образом:

  1. Предпочитать передавать «по значению», когда вы передаете атомарную, унитарную, неделимую сущность, такую ​​как одиночный неагрегатное значение любого типа - число, указатель, итератор. Обратите внимание, что, например, итераторы - это унитарные значения на логическом уровне. Поэтому предпочтительнее передавать итераторы по значению , независимо от того, больше ли их фактический размер, чем sizeof (void *). (Реализация STL делает именно это, кстати.)

  2. Предпочитайте передавать «по константной ссылке», когда вы передаете агрегированное, составное значение любого вида. т.е. значение, которое на логическом уровне обнаруживает явно "сложную" природу, даже если его размер не превышает sizeof (void *).

Разделение между ними не всегда ясно, но как всегда обстоят дела с все такие рекомендации. Более того, разделение на «атомарные» и «составные» объекты может зависеть от специфики вашего проекта, поэтому решение может фактически отличаться от одного проекта к другому.

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

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

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


В C ++ 11 введение семантики перемещения в язык привело к заметному сдвигу в относительных приоритетах различных методов передачи параметров. При определенных обстоятельствах может стать вполне возможным передавать даже сложные объекты по значению

Следует ли все / большинство функций-установщиков в C ++ 11 записывать как шаблоны функций, принимающие универсальные ссылки?

7
ответ дан 30 November 2019 в 09:58
поделиться

Это не будет иметь никакого значения для int, поскольку при использовании ссылки адрес памяти все равно должен быть передан, а адрес памяти (void *) обычно имеет размер целое число.

Для типов, содержащих много данных, это становится гораздо более эффективным, поскольку позволяет избежать огромных накладных расходов, связанных с необходимостью копирования данных.

1
ответ дан 30 November 2019 в 09:58
поделиться

Ссылка на const T не стоит усилий по типизации в случае скалярных типов, таких как int, double и т. Д. Практическое правило состоит в том, что типы классов должны приниматься через ref-to- const. Но для итераторов (которые могут быть типами классов) мы часто делаем исключение.

В общем коде вы, вероятно, должны чаще писать «T const &» на всякий случай. Также есть трейты вызова boost , которые можно использовать для выбора наиболее многообещающего типа передачи параметров. Насколько я могу судить, он в основном использует ref-to-const для типов классов и передачу по значению для скалярных типов.

Но есть также ситуации, когда вы можете захотеть принять параметры по значению, независимо от того, насколько дорого создание копия может быть. См. Статью Дейва «Хотите скорости? Используйте передачу по значению!» .

2
ответ дан 30 November 2019 в 09:58
поделиться

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

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

Мораль: напишите свои конструкторы копирования.

-1
ответ дан 30 November 2019 в 09:58
поделиться
Другие вопросы по тегам:

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