16byteアライメントを持つメンバを持つオブジェクトに対応
これまでxnew
普通のnewも同様に、関係なく配置します。
なのでアライメントの問題はどうしようもないだろう、と思っていたのですが、
ゲームにおいては、16byteアライメントを持つことはよくありうる、といったこともあり、対応することにしました。
どうやって対応するか、この一週間悩んでやっと実装できました。
xnewで生成されたオブジェクトは、16byteアライメントを持つメンバがある場合16byteアライメントを保障します。
持たないオブジェクトに関してはこれまでどおりです。
#include <xmmintrin.h> struct Vec128{ __m128 a; }; struct Spr{ Vec128 v; }; XTAL_BIND(Spr){ it->def_var("v", &Spr::v); } void test(){ Spr* p = new Spr(); _mm_add_ps(p->v.a, p->v.a); // これは危険 SmartPtr<Spr> s = xnew<Spr>(); _mm_add_ps(s->v.a, s->v.a); // xnewで確保した場合は大丈夫 }
-
-
- -
-
今回の実装の余波
AllocatorLibは次のようなインターフェイスと変更となりました。
class AllocatorLib{ public: virtual ~AllocatorLib(){} virtual void* malloc(std::size_t size); virtual void free(void* p, std::size_t size); virtual void* malloc_align(std::size_t size, std::size_t alignment); virtual void free_align(void* p, std::size_t size, std::size_t alignment); virtual void out_of_memory(){} };
malloc_align, free_alignが増えています。
ただし、これらは実装しなくてもかまいません。デフォルトの実装でmallocを使って整列するメモリを返すようになっています。
memalignなど、もっと効率のよい関数がある場合にオーバーライドしてください。
- -
また、RefCountingBase, Baseという基底クラスも修正しました。
仮想関数はすべてon_という接頭をつけた名前にリネームし、非仮想関数としました。
たとえばvirtual void rawmember();はvoid on_rawmember();となります。
デストラクタも非仮想とし、仮想関数を排除しました。
ただし、特別な仕組みを導入したため、それらは仮想関数と同様にオーバーライドできます。