Какая сигнатура лучше всего подходит для перегруженных арифметических операторов в C ++?

StackOverflow https://stackoverflow.com/questions/118630

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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

Но мне указали, что это тоже сработает:

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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

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

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

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

3.7.2/2:Автоматический срок хранения

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top