Что должно быть предпочтительнее, перемещение или пересылка аргументов

#c #move #template-argument-deduction

#c #двигаться #шаблон-аргумент-вывод

Вопрос:

Ниже приведен упрощенный пример шаблона List , где есть две append_move() append_forward() функции и, которые имеют одну и ту же цель, берут аргументы и помещают их в контейнер List . Первая append_move() функция принимает arg1 переданное значение, а затем перемещает его в emplace_back() функцию. Вторая append_move() функция использует автоматическое arg1 восстановление, а затем перенаправляет его в emplace_back() функцию.

Имеет ли append_forward() функция какие-либо преимущества перед append_move() функцией и какой функции следует отдать предпочтение?

 #include lt;dequegt; #include lt;stringgt; #include lt;utilitygt;  templatelt;typename Tgt; class List {  public:  void append_move(T arg1, std::string arg2)  {  list.emplace_back(std::move(arg1), std::move(arg2));  }   templatelt;typename Xgt;  void append_forward(Xamp;amp; arg1, std::string arg2)  {  list.emplace_back(std::forwardlt;Xgt;(arg1), std::move(arg2));  }   private:  std::dequelt;std::pairlt;T, std::stringgt;gt; list; };  

Комментарии:

1. Подумайте, что происходит, когда вы создаете что-то вроде Listlt;int amp;gt; . Вы хотите разрешить или запретить это?

2. добавить перемещение скопирует arg1 при вызове, append_forward не будет

3. @ChrisDodd Не будет работать, коллекции ссылок также не допускаются. (если вы не хотите специализироваться на шаблонах и начать использовать std::reference_wrapper)

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

5. @Kam, если T у вас есть какие-либо явные однопараметрические конструкторы, то эти два понятия даже не будут эквивалентны с семантической точки зрения.

Ответ №1:

Вперед или вперед

Если T деструктор не может быть оптимизирован и создает видимые побочные эффекты, например

 struct Loud { ~Loud() { std::cout lt;lt; "destructorn"; } };  

затем

 Listlt;Loudgt; list; Loud const loud; list.append_forward(loud);  

вызывает на один деструктор меньше, чем

 list.append_move(loud);  

поскольку последний создает еще один объект =gt; должен вызвать еще один деструктор. Таким образом, пересылка более предпочтительна.

Однако это делает API менее привлекательным:

 another_list.append_move({"some", "arguments"}); // works and pretty //another_list.append_forward({"some", "arguments"}); // doesn't compile another_list.append_forward(Foo{"some", "arguments"}); // works  

Перегрузка вручную

Так что, к сожалению, обеспечение рукописных перегрузок, по-видимому, является лучшим решением (для пользователя вашего кода) из этих трех:

 void append_overload(Tamp;amp; t); // TODO actually implement void append_overload(T constamp; t) { append_overload(T{t}); }  

Место

Однако (еще раз), если вас все это волнует, подумайте о том, чтобы разместить:

 templatelt;typename... Asgt; void append_emplace(Asamp;amp;... args) {  list.emplace_back(std::forwardlt;Asgt;(args)...); }  
 // works and pretty as long as you don't need to pass-construct two arguments another_list.append_emplace("some", "arguments");  

Другие перегрузки

Кроме того, если у вас больше append_* перегрузок, обратите внимание, что версии пересылки/размещения имеют меньший приоритет из-за того, что они являются шаблонами. Выбор за вами.

Комментарии:

1. Спасибо вам за исчерпывающий ответ. У меня есть два вопроса. 1) Когда вы говорили об одном деструкторе меньше , вы имеете в виду деструктор копии переданного объекта в параметре arg1 append_move() функции? 2) Меня немного смущает, что вы используете another_list.append_move() another_list.append_move() функции и с одним аргументом, потому что в моем примере я использую функции с двумя аргументами. Это просто для более легкого объяснения?

2. @Kam 1) Да; Кстати, в этом случае append_forward constamp; вместо этого получает, избегая создания (=gt; уничтожения) ненужного объекта. 2) Да; Кстати, реализация/использование append_emplace может быть неприятным в вашем случае (с двумя параметрами).