2013-09-16 4 views
7

я наткнулся на статью http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/Передача по значению и скопировать оптимизации Elision

Авторский Совет:

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

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

//Don't 
    T& T::operator=(T const& x) // x is a reference to the source 
    { 
     T tmp(x);   // copy construction of tmp does the hard work 
     swap(*this, tmp); // trade our resources for tmp's 
     return *this;  // our (old) resources get destroyed with tmp 
    } 

против

// DO 
    T& operator=(T x) // x is a copy of the source; hard work already done 
    { 
     swap(*this, x); // trade our resources for x's 
     return *this; // our (old) resources get destroyed with x 
    } 

В обоих случаях создается одна дополнительная переменная , так где же выгоды? Единственное преимущество, которое я вижу, заключается в том, что временный объект передается во второй пример.

+1

Если источник является временным: 'obj = T();' или 'obj = foo();' где 'foo()' возвращает 'T'. – juanchopanza

+1

Это на самом деле не очень хороший совет. Он раскрывает то, что должно быть детальностью реализации (копируете ли вы аргумент или нет) в интерфейсе, что является крайне плохой разработкой программного обеспечения. Могут быть моменты, когда профайлер говорит, что вам нужно, но в остальном вы придерживаетесь правил кодирования. (Вездесущее руководство, по-видимому, относится к классам классов пропуска по ссылке, все остальное по стоимости, хотя это тоже можно рассматривать как преждевременную оптимизацию.) –

+3

@jameskanze «эта функция копирует состояние аргумента» является разумной функцией интерфейса. Помимо всего прочего, это влияет на стоимость, оно говорит вам, какие функции типа аргументов должны быть реализованы, и даже информирует пользователя о функциональности. Часть гения C++ 11 заключалась в том, что копирование и перемещение важны, а районные операции с данными - и важно, чтобы это происходило. – Yakk

ответ

6

Дело в том, что в зависимости от того, как вызван оператор, копия может быть удалена. Предположим, вы используете оператор, как это:

extern T f(); 
... 
T value; 
value = f(); 

Если аргумент принимается путем T const& компилятор не имеет никакого выбора, кроме как провести на временной и передать ссылку на ваш оператор присваивания. С другой стороны, когда вы передаете аргумент по значению, то есть он использует T, значение, возвращаемое с f(), может быть расположено там, где этот аргумент, тем самым лидируя одну копию. Если аргумент присваивания является значением lvalue в той или иной форме, его всегда необходимо скопировать, конечно.

+3

Существует также разница в исключениях. В случае «T const &» конструктор копирования может вызывать исключение внутри вызываемой функции, но в случае «T» исключение будет выбрано вместо контекстного вызова * (это означает, что оператор присваивания может быть отмеченным 'noexcept', даже если конструктор копирования может выдать). – Simple

+0

@ Простой: На самом деле это интересный момент! Хотя, в конце концов, это не имеет большого значения: все выражение все равно может бросить. Это может облегчить создание шаблонов, которые не обязательно будут устранены с помощью условного 'noexcept' в результате. –

+1

Копия во втором случае также может быть заменена ходом, который является районом от элиции. – Yakk