встроенный void addTask (задача Task) против встроенного void addTask (const Task & task)

0

Я использовал любую сложную структуру по const & или по крайней мере с помощью &. Но с новой семантикой std::move и всеми оптимизациями, которые предлагают сегодня компиляторы, остается ли это вариант?

Рассмотрим такой пример:

struct Task{
    unsigned timeMS;
    void(*function)(unsigned, unsigned) = 0;
    Task(unsigned timeMS, void(*function)(unsigned, unsigned)) 
        : timeMS(timeMS), function(function){}
};

class Timeline{
    std::vector<Task> tasks;
    ...
};

class App{
...
public:
    inline void addTask1(const Task &task){ timeline.add(Task); }
    inline void addTask2(Task &task){ timeline.add(Task); }
    inline void addTask3(Task task){ timeline.add(Task); }
};

Какой из addTask1, addTask2, addTask3 - путь? Предположим, что App::addTask() - сильно используемый метод.

Я предполагаю, что const & требует создания копии, но я узнал, что все не так просто, как они выглядят. Этого достаточно, чтобы упомянуть RVO (http://en.wikipedia.org/wiki/Return_value_optimization) - и я уверен, что есть гораздо больше вещей, которые следует учитывать (и я еще не знаю их).

Я знаю, что inline - это просто предложение для компилятора, а не заказ. Но что это меняет в const & VS & против by value битвы?

Я работаю с VC++ 2013, я не слишком сосредоточен на gcc.

Ps Обратите внимание, что App::addTask вызывает Timeline::add какой vector::push_back вызова vector::push_back. Таким образом, параметр передается более одного раза - должен ли я делать как App::addTask и Timeline::add тот же "тип" (const & vs & vs by value).

  • 0
    Перемещение не помогает вообще, но я был бы удивлен, если бы const& или значение компилировались бы в нечто иное после inline.
  • 0
    Функции-члены, определенные в определении класса, неявно встроены
Показать ещё 2 комментария
Теги:
c++11
pass-by-reference
move-semantics

1 ответ

3
Лучший ответ

Независимо от того, выполняется ли значение по значению или const& зависит, очевидно, что сделано дальше с объектом. Особенно, когда копия объекта необходима в той или иной форме, и передаваемые объекты, скорее всего, происходят из временных объектов, вероятно, предпочтительнее использовать пропуск по значению: при передаче по значению компилятору разрешается исключать копию. Когда передача const& copy elision не разрешена (для копирования копии необходимо, чтобы компилятор должен был доказать, что создание копии не имеет наблюдаемых побочных эффектов).

Конечно, при передаче по значению значение оказывается равным lvalue, т.е. Чтобы оно перемещалось, а не копировалось, вам нужно будет std::move() при передаче (дальнейшая копия не может быть удалена в любом случае ):

void addTask3(Task task) { timeline.add(std::move(task)); }

BTW, вы опустили идеальную версию для пересылки:

template <typename T>
void addTask4(T&& task) { timeline.add(std::forward<T>(task)); }

Эта версия также не будет разрешена для копирования копий, но она может иметь преимущество для создания более дорогой версии in-situ на основе подходящего преобразования.

Тем не менее, у меня нет никаких критериев, чтобы определить разницу. Если кто-то может предложить достойный способ оценить различия, я с удовольствием добавлю соответствующий тест в свой набор тестов и добавлю этот ответ к результатам.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню