Отличается от сборки для передачи по значению и передачи по const ref - PullRequest
0 голосов
/ 11 октября 2018

Предположим, у нас есть такой код:

template<typename T>
struct StrongValue{
    constexpr const T &operator()() const {
        return value;
    }

    T &operator()(){
        return value;
    }

    constexpr const T &get() const {
        return value;
    }

    T &get(){
        return value;
    }

    T value;
};

using myint = int; // try double too

using m = StrongValue<myint>;

myint sum2(const m &a, const m &b){
    return a() + b();
}

myint sum2a(const m a, const m b){
    return a() + b();
}

myint sum1(myint a, myint b){
    return a + b;
}

int main(){
    constexpr m a{5};
    constexpr m b{5};

    return sum2a(a, b);
}

как в clang, так и в gcc, -O3 выглядит так:

sum2(StrongValue<int> const&, StrongValue<int> const&):
  mov eax, DWORD PTR [rsi]
  add eax, DWORD PTR [rdi]
  ret
sum2a(StrongValue<int>, StrongValue<int>):
  lea eax, [rdi+rsi]
  ret
sum1(int, int):
  lea eax, [rdi+rsi]
  ret
main:
  mov eax, 10
  ret

Почему sum2 скомпилирован так?

Это потому, что компилятор изменит сигнатуру функции, если пропустит ссылку, поэтому ему это запрещено.

Означает ли это, если не встроено, sum2дороже, чем sum2a?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Почему sum2 компилируется следующим образом?

Это ожидаемо.Для sum2 вы передаете две ссылки.Ссылка и const - это вещи C ++, у процессоров их нет, для процессоров - просто указатели.Поэтому в функции код должен извлечь два значения из памяти и суммировать их.

Две другие версии получают аргументы по значению.

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

Означает ли это, что если сумма не указана, sum2 дороже sum2a?

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

0 голосов
/ 11 октября 2018

Разница в том, что параметры для sum2 по сути являются указателями, а параметры для sum2a являются значениями.Это означает, что в sum2 указатели должны быть разыменованы, чтобы получить действительные значения, которые затем могут быть добавлены, в то время как в sum2a вы можете добавлять значения сразу.

Распространенной ошибкой является чрезмерное использование константных ссылок.Для объектов с дешевым копированием часто лучше передавать параметры по значению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...