В традиционном C ++ передача по значению в функции и методы является медленной для больших объектов и обычно не одобряется. Вместо этого программисты на C ++ стремятся передавать ссылки, что быстрее, но при этом возникает множество сложных вопросов, касающихся владения и особенно управления памятью (в случае, если объект выделен в куче).
Теперь, в C ++ 11, у нас есть ссылки на Rvalue и конструкторы перемещения, что означает, что можно реализовать большой объект (такой как std::vector
), который дешево передавать по значению в функцию и из нее .
Итак, означает ли это, что по умолчанию должен передаваться по значению для экземпляров таких типов, как std::vector
и std::string
? Как насчет пользовательских объектов? Какова новая лучшая практика?
c++
coding-style
c++11
Дерек Турн
источник
источник
pass by reference ... which introduces all sorts of complicated questions around ownership and especially around memory management (in the event that the object is heap-allocated)
, Я не понимаю, как это сложно или проблематично для владельца? Может быть, я что-то пропустил?const std::string&
а не как копию. Затем вышел первый поток ...Ответы:
Это разумное значение по умолчанию, если вам нужно сделать копию внутри тела. Это то , что Дэйв Абрамс выступает :
В коде это означает, что не делайте этого:
но сделайте это:
который имеет преимущество, которое может использовать вызывающий
foo
сторона так:и только минимальная работа сделана. Вам нужно две перегрузки, чтобы сделать то же самое со ссылками,
void foo(T const&);
иvoid foo(T&&);
.Имея это в виду, я теперь написал свои ценные конструкторы как таковые:
В противном случае передача по ссылке на
const
все еще является разумной.источник
SomeProperty p;
for (auto x: vec) { x.foo(p); }
, не подходит. Кроме того, конструкторы перемещения имеют стоимость (чем больше объект, тем выше стоимость), хотяconst&
по существу бесплатны.std::vector
с миллионом элементов стоит столько же, сколько перемещение с пятью элементами, поскольку перемещается только указатель на массив в куче, а не каждый объект в векторе. Так что это на самом деле не такая уж большая проблема.std::move
повсюду ..const&
, который несколько раз сбил меня с толку.void foo(const T&); int main() { S s; foo(s); }
, Это может скомпилировать, даже если типы разные, если есть конструктор T, который принимает S в качестве аргумента. Это может быть медленным, потому что большой T-объект может быть создан. Вы можете подумать, что передали ссылку, не копируя, но, возможно, так оно и есть. Смотрите этот ответ на вопрос, который я задал для более. В основном,&
обычно привязывается только к lvalues, но есть исключение дляrvalue
. Есть альтернативы.Почти во всех случаях ваша семантика должна быть либо:
Все остальные подписи должны использоваться только экономно и с достаточным основанием. Компилятор теперь всегда будет работать наиболее эффективным способом. Вы можете просто продолжить писать свой код!
источник
foo(bar& x) { x.a = 3; }
Это чертовски намного надежнее (и читабельнее!), Чемfoo(bar* x) {if (!x) throw std::invalid_argument("x"); x->a = 3;
ref
ключевое слово в C #).is shared_ptr intended to never be null? Much as (I think) unique_ptr is?
Оба эти предположения неверны.unique_ptr
иshared_ptr
может содержать нуль /nullptr
значения. Если вы не хотите беспокоиться о нулевых значениях, вы должны использовать ссылки, потому что они никогда не могут быть нулевыми. Вам также не придется печатать->
, что вас раздражает :)Передайте параметры по значению, если внутри тела функции вам нужна копия объекта или вам нужно только переместить объект. Пройти мимо
const&
если вам нужен только не мутирующий доступ к объекту.Пример копирования объекта:
Пример перемещения объекта:
Пример не мутирующего доступа:
Для обоснования, см. Эти сообщения в блоге Дэйва Абрахамса и Сян Фана .
источник
Подпись функции должна отражать ее предполагаемое использование. Читаемость важна и для оптимизатора.
Это лучшее предварительное условие для оптимизатора для создания самого быстрого кода - по крайней мере в теории, а если не в реальности, то через несколько лет.
Вопросы производительности очень часто переоцениваются в контексте передачи параметров. Идеальная пересылка - пример. Такие функции, как
emplace_back
правило, в основном очень короткие и встроенные.источник