Скажем, я хочу реализовать функцию, которая должна обрабатывать объект и возвращать новый (возможно, измененный) объект. Я хотел бы сделать это как можно эффективнее в C + 11. Окружающая среда выглядит следующим образом:
class Object {
/* Implementation of Object */
Object & makeChanges();
};
Альтернативы, которые приходят мне на ум:
// First alternative:
Object process1(Object arg) { return arg.makeChanges(); }
// Second alternative:
Object process2(Object const & arg) { return Object(arg).makeChanges(); }
Object process2(Object && arg) { return std::move(arg.makeChanges()); }
// Third alternative:
Object process3(Object const & arg) {
Object retObj = arg; retObj.makeChanges(); return retObj;
}
Object process3(Object && arg) { std::move(return arg.makeChanges()); }
Примечание. Я хотел бы использовать функцию обертки, такую как process()
, потому что она будет выполнять некоторую другую работу, и я хотел бы иметь как можно больше повторного использования кода.
Обновление:
Я использовал makeChanges()
с данной сигнатурой, потому что объекты, с которыми я имею дело, предоставляют методы с этим типом подписи. Я предполагаю, что они использовали это для цепочки методов. Я также исправил две упомянутые синтаксические ошибки. Спасибо, что указали на них. Я также добавил третий вариант, и я остановлюсь на следующем вопросе.
Попытка их с помощью clang [т.е. Object obj2 = process(obj);
] приводит к следующему:
Первая опция делает два вызова конструктора копирования; один для передачи аргумента и один для возврата. Вместо этого можно сказать return std::move(..)
и иметь один вызов конструктора копирования и один вызов конструктора перемещения. Я понимаю, что RVO не может избавиться от одного из этих вызовов, потому что мы имеем дело с параметром функции.
Во втором варианте у нас все еще есть два вызова конструктора копирования. Здесь мы делаем один явный вызов, а один - при возврате. Я ожидал, что RVO ударит и избавится от последнего, поскольку возвращаемый объект - это другой объект, чем аргумент. Однако этого не произошло.
В третьем варианте у нас есть только один вызов конструктора копирования, и это явный. (N) RVO исключает вызов конструктора копирования, который мы будем делать для возврата.
Мои вопросы таковы:
- (ответил) Почему RVO пинает последний параметр, а не второй?
- Есть ли лучший способ сделать это?
- Если бы мы проходили во временном, 2-м и 3-м вариантах, вы вызывали бы конструктор перемещения при возврате. Возможно ли исключить использование (N) RVO?
Спасибо!