Является ли pass-by-value разумным дефолтом в C ++ 11?

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

Теперь, в C ++ 11, мы имеем ссылки Rvalue и перемещаем конструкторы, а это означает, что можно реализовать большой объект (например, std::vector ), который дешево передавать по значению в функцию и из нее.

Итак, означает ли это, что по умолчанию должно быть передано по значению для экземпляров таких типов, как std::vector и std::string ? Как насчет пользовательских объектов? Какая новая лучшая практика?

Это разумный вариант, если вам нужно сделать копию внутри тела. Об этом говорит Дейв Абрахамс:

Указание: не копируйте аргументы функции. Вместо этого передайте их по значению и пусть компилятор выполнит копирование.

В коде это не означает:

 void foo(T const& t) { auto copy = t; // ... } 

но сделайте следующее:

 void foo(T t) { // ... } 

который имеет то преимущество, что вызывающий может использовать foo так:

 T lval; foo(lval); // copy from lvalue foo(T {}); // (potential) move from prvalue foo(std::move(lval)); // (potential) move from xvalue 

и выполняется только минимальная работа. Вам понадобится две перегрузки, чтобы сделать то же самое со ссылками, void foo(T const&); и void foo(T&&); ,

Имея это в виду, я теперь написал мои ценные конструкторы как таковые:

 class T { U u; V v; public: T(U u, V v) : u(std::move(u)) , v(std::move(v)) {} }; 

В противном случае переход по ссылке на const прежнему является разумным.

Почти во всех случаях ваша семантика должна быть либо:

 bar(foo f); // want to obtain a copy of f bar(const foo& f); // want to read f bar(foo& f); // want to modify f 

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

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

Пример копирования экземпляра:

 void copy_antipattern(T const& t) { // (Don't do this.) auto copy = t; t.some_mutating_function(); } void copy_pattern(T t) { // (Do this instead.) t.some_mutating_function(); } 

Пример перемещения объекта:

 std::vector v; void move_antipattern(T const& t) { v.push_back(t); } void move_pattern(T t) { v.push_back(std::move(t)); } 

Пример без мутирующего доступа:

 void read_pattern(T const& t) { t.some_const_function(); } 

Для обоснования см. Эти сообщения в блоге Дейвом Абрахамом и Сян Фан .

Давайте будем гением компьютера.