2015-01-19 3 views
1

мне было интересно, если:Использует указатели и ссылки объекта как аргументы функции легче?

//Let's say T is a big class with + operand implemented. 
T add(T* one, T* two) 
{ 
    return *one + *two; 
} 

и:

T add(T& one, T& two) 
{ 
    return one + two; 
} 

легче, чем это:

T add (T one, T two) 
{ 
    return one +two; 
} 

Если нет, то почему бы кто-то использовать указатели или ссылки на объект вместо самих объектов в качестве аргументов функции, если ничто не изменит данные объекта?

+0

У вас есть случай, когда кто-то это делает? Это, конечно, не «легче» (и «int' не являются »объектами»). – Thilo

+0

Для полноты вы должны добавить принятие 'const &' и '&&'. – Deduplicator

+1

Вам нужно предоставить больше контекста. –

ответ

4

Для легких типов, то есть тех, которые вписываются в регистр, например int, это не имеет никакого значения, поскольку их так же легко скопировать, как указатель на них. На самом деле, дополнительная косвенность может навредить производительности, поэтому вам следует избегать ее, если это не нужно.
Однако используемые типы могут быть дорогими для копирования. Пример каждый день - std::string. Ссылки избегают копий и предпочитаются везде, где функция требует «тяжелых» объектов.

В шаблонах функций обычно следует использовать ссылки при использовании различных типов объектов, если только вы не уверены, что только такие типы являются «легкими», такими как итераторы или скаляры.
Тем не менее, существуют менее очевидные исключения из этого правила.Рассмотрим std::accumulate:

template< class InputIt, class T > 
T accumulate(InputIt first, InputIt last, T init); 

Здесь init принимается значение. Причина довольно проста: в обычных реализациях initизменен как есть непосредственно Используется внутри вычислений - не вводится промежуточный объект.

template<class InputIt, class T> 
T accumulate(InputIt first, InputIt last, T init) 
{ 
    for (; first != last; ++first) { 
     init = init + *first; // Here 
    } 
    return init; 
} 

Указатели не должны использоваться для косвенных функциональных параметров. Они используются в C, где ссылок не существует.

+0

«Указатели сами по себе не должны использоваться для косвенных параметров функции». Не могли бы вы рассказать об этом? –

+0

@NeilKirk Если вы не работаете с адресами или не хотите хранить ссылки («общие» ссылки, т. Е. Материал, относящийся к объекту), я не вижу причин брать указатель на объект, с которым вы хотите работать. Ссылки работают также (и избегают синтаксического уродства), а перегрузка позволяет вам писать версии метода, которые принимают или не принимают аргумент. – Columbo

1

Нет, ваша последняя версия «легче».

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

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

+0

Ваше последнее предложение неверно. Ссылки так же хороши, как указатели на этот случай (ИМХО еще лучше). – leemes

+0

@leemes: Это просто терминология. Под обложками ссылки являются указателями. –

3

Если «лёгкий» означает «более эффективный», ответ (для ints) не является - единственный аргумент времени, передаваемый указателем или ссылкой, может быть более эффективным, если передача по значению - это если объект, который вы передача очень велика (например, sizeof (theObjectType) значительно больше, чем 4 или 8 байтов, что является типичным размером указателя), или если класс объекта имеет конструктор копирования, реализация которого является дорогостоящим по вычислительной стоимости. Обратите внимание, что при передаче по указателю или по ссылке ЦП должен разыменовывать указатель/ссылку при доступе к данным, что не является полностью бесплатным.

Если нет, то почему бы кто-то использовать указатели или ссылки на объект вместо самих объектов в качестве аргументов функции, если ничего не изменит данные объекта?

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

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

1

Ответ, как часто бывает: От этого зависит.

Если вы хотите знать, является ли копирование или передача по ссылке дешевле, или правильно, считают это:

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

    Для int указатель/ссылка в лучшем случае не стоит дороже.

  2. Помните, что преимущества уменьшенного наложения.
  3. Помните, что вы всегда можете беспощадно грабить аргументы, передаваемые по значению, точно так же, как и те, которые были переданы rvalue-reference.
    Не так для других.

    Не то, чтобы эти соображения имели значение для int или других типов, не управляющих более дорогими ресурсами.

  4. Имеет ли смысл опустить аргумент полностью?
    В этом случае вам нужно пройти указателем или использовать что-то вроде будущего std::optional.
    Если нет, указатели - это семантически неправильный выбор.

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

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

4

При использовании примитивного типа, передайте указатель или ссылку, он не светлее, чем пройден по значению. Но если это большой объект, то передать указатель или ссылку будет легче, чем передавать по значению из-за накладных расходов при копировании большого объекта.

Смежные вопросы