1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VisualStudioのstd::allocate_sharedを使用すると型のアライメント要求が小さくなる

Posted at

問題

VisualStudio2015でstd::allocate_sharedを使用した時に、型のアライメント要求が指定より小さくなる問題が発生した。型のアライメント要求は16であった。

原因

ライブラリ内部で定義されるstd::aligned_union<1, T>のアライメント要求が、Tのアライメント要求と異なるのが原因であった。

解決方法

この問題を、std::allocatorをカスタマイズしてrebind前の型の情報を保存しておき、最もアライメント要求の大きい数値を選択する事で回避した。

以下は、確認用のコードである。
rebindされた時にTを可変引数テンプレートに保存している。

#include <memory>
#include <iostream>

template <class... Types>
void print()
{
    struct info
    {
        char const* name;
        size_t size;
        size_t align;
    };
    for (auto&& it : { info{typeid(Types).name(), sizeof(Types), alignof(Types)}... }) {
        std::cout << it.name << " size=" << it.size << " align=" << it.align << std::endl;
    }
}

template <class T, class... Binds>
struct my_allocator : std::allocator<T>
{
    template <class U>
    struct rebind
    {
        using other = my_allocator<U, Binds..., T>;
    };
    my_allocator() = default;
    
    template <class U, class... Any>
    my_allocator(my_allocator<U, Any...> const&) {}
    
    template <class... Args>
    auto allocate(Args&&... args) {
        print<Binds..., T>();
        return std::allocator<T>::allocate(std::forward<Args>(args)...);
    }
};

int main() {
    struct alignas(16) X {};
    auto x = std::allocate_shared<X>(my_allocator<X>());
}

確認

上記コードをclangでコンパイルして実行すると以下の出力を得る

Z4mainE1X size=16 align=16
NSt3__120__shared_ptr_emplaceIZ4mainE1X12my_allocatorIS1_JEEEE size=48 align=16

Xのアライメント要求は16で、rebind後のTのアライメント要求も16である事が判る。
一方、VisualStudio2015でコンパイルして実行すると以下の出力を得る

struct `int __cdecl main(void)'::`2'::X size=16 align=16
class std::_Ref_count_obj_alloc<struct `int __cdecl main(void)'::`2'::X,struct my_allocator<struct `int __cdecl main(void)'::`2'::X> > size=32 align=8

VisualStudio2015では、Xのアライメント要求16に対して、rebind後のTのアラインメント要求は8である事が判る。よってTのアライメント要求でストレージを確保すると、オブジェクトが期待したアドレスに配置されない場合がある。

なお、VisualStudio2017でも同様の出力である。

struct `int __cdecl main(void)'::`2'::X size=16 align=16
class std::_Ref_count_obj_alloc<struct `int __cdecl main(void)'::`2'::X,struct my_allocator<struct `int __cdecl main(void)'::`2'::X> > size=32 align=8

結論

VisualStudioでstd::allocate_sharedを使用する場合はアライメントに注意した方が良い。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?