Какова лучшая сигнатура для перегруженных арифметических операторов в C ++? - PullRequest
1 голос
/ 23 сентября 2008

Я предполагал, что каноническая форма для оператора +, предполагая существование перегруженного оператора + = функция-член, была такой:

const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs) +=rhs;
}

Но мне было указано, что это также будет работать:

const T operator+ (T lhs, const T& rhs)
{
    return lhs+=rhs;
}

По сути, эта форма переносит создание временного объекта из тела реализации в вызов функции.

Кажется немного неловким иметь разные типы для двух параметров, но есть ли что-то не так со второй формой? Есть ли причина отдавать предпочтение одному другому?

Ответы [ 7 ]

4 голосов
/ 23 сентября 2008

Я не уверен, есть ли большая разница в сгенерированном коде для любого из них.

Между этими двумя я бы (лично) предпочел бы первую форму, поскольку она лучше передает намерение. Это касается как повторного использования оператора + =, так и способа передачи шаблонизированных типов с помощью const &.

2 голосов
/ 23 сентября 2008

Я бы предпочел первую форму для удобства чтения.

Мне пришлось дважды подумать, прежде чем я увидел, что копируется первый параметр. Я этого не ожидал. Поэтому, поскольку обе версии, вероятно, одинаково эффективны, я бы выбрал ту, которую легче читать.

2 голосов
/ 23 сентября 2008

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

Исследования по теме оптимизации возвращаемого значения , например, эта ссылка в качестве быстрого примера: http://www.cs.cmu.edu/~gilpin/c++/performance.html

1 голос
/ 23 сентября 2008

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

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

1 голос
/ 23 сентября 2008
const T operator+(const T& lhs, const T& rhs)
{
    return T(lhs)+=rhs;
}

почему бы и нет, если вы хотите краткость?

0 голосов
/ 02 ноября 2008

Я думаю, что если вы добавите их обоих (я хотел бы, так как они просто пересылают функции, и, предположительно, функция operator + = () не в строке), вы бы практически не различали генерацию кода. Тем не менее, первое является более каноническим. Вторая версия неоправданно «милашка».

0 голосов
/ 02 ноября 2008

На самом деле второе предпочтительнее. Как указано в стандарте c ++,

3.7.2 / 2: длительность автоматического хранения

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

То есть, поскольку неназванный временный объект создается с помощью конструктора копирования, компилятор может не использовать оптимизацию возвращаемого значения. Однако для второго случая возможна оптимизация безымянного возвращаемого значения. Обратите внимание, что если ваш компилятор реализует именованную оптимизацию возвращаемого значения, лучшим кодом будет

const T operator+(const T& lhs, const T& rhs)
{
    T temp(lhs);
    temp +=rhs;
    return temp;
}
...