Saya memiliki beberapa kelas vektor di mana fungsi aritmatika terlihat seperti ini:
template<typename T, typename U>
auto operator*(const Vector3<T>& lhs, const Vector3<U>& rhs)
{
return Vector3<decltype(lhs.x*rhs.x)>(
lhs.x + rhs.x,
lhs.y + rhs.y,
lhs.z + rhs.z
);
}
template<typename T, typename U>
Vector3<T>& operator*=(Vector3<T>& lhs, const Vector3<U>& rhs)
{
lhs.x *= rhs.x;
lhs.y *= rhs.y;
lhs.z *= rhs.z;
return lhs;
}
Saya ingin melakukan sedikit pembersihan untuk menghapus kode duplikat. Pada dasarnya, saya ingin mengonversi semua operator*
fungsi untuk memanggil operator*=
fungsi-fungsi seperti ini:
template<typename T, typename U>
auto operator*(const Vector3<T>& lhs, const Vector3<U>& rhs)
{
Vector3<decltype(lhs.x*rhs.x)> result = lhs;
result *= rhs;
return result;
}
Tapi saya khawatir apakah itu akan menimbulkan overhead tambahan dari panggilan fungsi tambahan.
Apakah itu ide yang bagus? Ide buruk?
c++
mathematics
performance
refactoring
pengguna112513312
sumber
sumber
*
dan*=
sedang melakukan dua hal yang berbeda - yang pertama menambahkan nilai individu, yang terakhir mengalikannya. Mereka juga tampaknya memiliki tipe tanda tangan yang berbeda.Jawaban:
Dalam praktiknya, tidak ada biaya tambahan yang akan dikeluarkan . Dalam C ++, fungsi-fungsi kecil biasanya digarisbawahi oleh kompiler sebagai optimisasi, sehingga rakitan yang dihasilkan akan memiliki semua operasi di callsite - fungsi tidak akan saling memanggil, karena fungsi tidak akan ada dalam kode akhir, hanya saja operasi matematika.
Bergantung pada kompilernya, Anda mungkin melihat salah satu dari fungsi-fungsi ini memanggil yang lain tanpa optimasi yang rendah (seperti debug build). Pada tingkat optimisasi yang lebih tinggi (rilis rilis), mereka akan dioptimalkan hingga hanya matematika.
Jika Anda masih ingin bertele-tele tentang hal itu (misalnya Anda membuat perpustakaan), menambahkan
inline
kata kunci keoperator*()
(dan fungsi pembungkus serupa) dapat mengisyaratkan kompiler Anda untuk melakukan inline, atau menggunakan flag / sintaks khusus kompiler seperti:-finline-small-functions
,-finline-functions
,-findirect-inlining
,__attribute__((always_inline))
(kredit untuk @Stephane Hockenhull ini info berguna di komentar) . Secara pribadi, saya cenderung mengikuti apa yang dilakukan framework / libs yang saya gunakan — jika saya menggunakan perpustakaan matematika GLKit, saya hanya akan menggunakanGLK_INLINE
makro yang disediakannya juga.Periksa ulang menggunakan Dentang (Xcode 7.2 Apple LLVM versi 7.0.2 / clang-700.1.81) ,
main()
fungsi berikut (dalam kombinasi dengan fungsi Anda danVector3<T>
implementasi naif ):kompilasi ke majelis ini menggunakan bendera optimisasi
-O0
:Di atas,
__ZmlIiiE7Vector3IDTmldtfp_1xdtfp0_1xEERKS0_IT_ERKS0_IT0_E
adalahoperator*()
fungsi Anda dan akhirnya fungsicallq
lain__…Vector3…
. Jumlahnya cukup banyak perakitan. Kompilasi dengan-O1
hampir sama, masih memanggil__…Vector3…
fungsi.Namun, ketika kita menabraknya
-O2
,callq
s__…Vector3…
menghilang, diganti denganimull
instruksi (* a.z
≈* 3
),addl
instruksi (* a.y
≈* 2
), dan hanya menggunakanb.x
nilai straight-up (karena* a.x
≈* 1
).Untuk kode ini, perakitan di
-O2
,-O3
,-Os
, &-Ofast
semua tampilan yang identik.sumber
inline void foo (const char) __attribute__((always_inline));
). Jika Anda ingin hal-hal vektor-berat berjalan pada kecepatan yang masuk akal sementara masih bisa ditawaraddl %edx, %edx
(yaitu menambahkan nilai ke dirinya sendiri).