Предпочитайте статические методы классов

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

struct Foo {
    // .. some members
    void SophisticatedCopy(const unsigned* src, unsigned* dst) {
        // .. sophisticated algorithm
    }
} foo;

void bar(){
    foo.SophisticatedCopy(src, dst);
}

При вызове метода класса происходит неявная передача указателя this в функцию. Это прекрасно видно в генерируемом ассемблере (спасибо, Matt Godbolt!):

foo DB 01H DUP (?)
bar PROC
sub rsp, 40 ; 00000028H
mov r8, QWORD PTR dst
mov rdx, QWORD PTR src
lea rcx, OFFSET FLAT:foo   // <-------
call Foo::SophisticatedCopy
add rsp, 40 ; 00000028H
ret 0
bar ENDP
Foo::SophisticatedCopy, COMDAT PROC
mov QWORD PTR [rsp+24], r8
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx // <-------
ret 0
Foo::SophisticatedCopy ENDP

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

struct Foo {
    // .. some members
    static void SophisticatedCopyStatic(const unsigned* src, unsigned* dst) {
        // .. sophisticated algorithm
    }
} foo;

void bar_static(){
    foo.SophisticatedCopyStatic(src, dst);
}

Оказывается, что можем!

bar_static PROC
sub rsp, 40 ; 00000028H
mov rdx, QWORD PTR dst
mov rcx, QWORD PTR src
call Foo::SophisticatedCopyStatic
add rsp, 40 ; 00000028H
ret 0
bar_static ENDP
Foo::SophisticatedCopyStatic, COMDAT PROC
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx
ret 0
Foo::SophisticatedCopyStatic ENDP

Вы можете сказать: “Зачем мне пытаться сэкономить две процессорные инструкции? Они же дешёвые,” — и в большинстве случаев будете правы. Однако, представьте систему (чаще всего, реального времени), которая вызывает эту функцию десять тысяч раз в секунду. Это двадцать тысяч лишних инструкций, в которых нет абсолютно никакого смысла. Это маленькая оптимизация, которая дает очень хороший выигрыш.


© 2018. All rights reserved.

Powered by Hydejack v7.5.1