Self Registrator Link Optimization Problem

Self registrator, atau bisa juga disebut registry pattern adalah trik yang digunakan untuk mendaftarkan tipe class ke object factory (wikipedia).

Sebagai contoh, terdapat class Object dan ObjectFactory. Tugas ObjectFactory adalah meng-instansiasi suatu object dengan Tipe Object (atau turunannya) dan mengembalikan object tersebut ke user. Salah satu contoh API yang dapat digunakan oleh user adalah dengan memanggil

Untuk dapat lebih berguna, ObjectFactory tentunya memiliki tipe-tipe lainnya selain DerivedType. Tipe-tipe ini perlu didaftarkan terlebih dahulu ke ObjectFactory sehingga jika user memberikan parameter “SomeOtherType”, ObjectFactory tau tipe object apa yang perlu diinstansiasi dan dikembalikan ke user. Salah satu cara mendaftarkan tipe tersebut adalah dengan menggunakan Self Registrator pattern.

Penulis class ObjectFactory dapat menyediakan API dibawah ini untuk dapat digunakan oleh penulis DerivedObject :

Kemudian, penulis class DerivedType dapat mendaftarkan class-nya dengan menggunakan code berikut :

Masalah kemudian timbul jika DerivedType didefinisikan di static libary terpisah yang membuat linker mengira DerivedType tidak pernah digunakan yang kemudian membuat linker tidak memasukkan definisi tersebut sehingga DerivedType tidak pernah didaftarkan di ObjectFactory. Mengutip dari cppreference,

Deferred dynamic initialization
It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.
If the initialization of a non-inline variable is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library). However, as long as anything from a TU is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.

Perilaku ini dibolehkan oleh standar karena DerivedObject (atau apapun yang didefinisikan di translation unit tersebut) tidak pernah di-“referensikan”. Salah satu solusi adalah dengan memaksa linker untuk load semua simbol pada libary di mana DerivedObject didefinisikan yaitu dengan menggunakan flag “/WHOLEARCHIVE” di MSVC, “–whole-archive” untuk g++ di Linux, dan “force_load” untuk XCode di OSX.

Untuk kode lebih detil dapat dilihat diĀ https://github.com/bysreg/self_registrator

Leave a Reply

Your email address will not be published. Required fields are marked *