对齐存储和标准布局

时间:2013-12-12 18:15:19

标签: c++ c++11

考虑以下C ++ 11代码:

#include <type_traits>

struct bar
{
    virtual void do_bar() const {}
};

struct foo
{
    std::aligned_storage<sizeof(bar),alignof(bar)>::type m_storage;
};
由于虚函数bar

do_bar()不是标准布局。但是,foo是标准布局,因为std::aligned_storage提供的类型是POD类型,foo满足标准布局类型的所有其他要求。

当我使用展示位置m_storage的{​​{1}}存储空间来构建new的实例时会发生什么?如,

bar

这合法吗?我可以用它来欺骗我对标准布局类型的限制吗?

3 个答案:

答案 0 :(得分:1)

这是你的代码:

struct bar {
    virtual void do_bar() const {}
};

struct foo {
    std::aligned_storage<sizeof(bar), alignof(bar)>::type m_storage;
};

这很好。 struct foo是标准布局类型,并且在给定实例foo myFoo的情况下,您可以将bar类型的对象构造为myFoo.m_storage

然而,这对编译器的POV来说完全没有意义,为什么还要烦恼呢?正如@dyp在评论中明智地说,“你为什么想要 foo成为标准布局?”

你挥挥手谈论工会。嗯,那没关系。你可以这样写:

union DoesntWork {
    bar b;    // compiler error in C++11 due to non-standard-layout type
    int i;
};

union DoesWork {
    foo f;    // works fine in C++11, of course
    int i;
};

然而,同样明显的是,你不能指望这个

struct car {
    int initialsequence;
};
struct bar {
    int initialsequence;
    virtual void do_bar() const {}
};
struct foo {
    std::aligned_storage<sizeof(bar), alignof(bar)>::type m_storage;
    bar& asBar() { return *reinterpret_cast<bar*>(&m_storage); }
};

union JustSilly {
    foo f;
    car c;
} js;
assert(&js.c.initialsequence ==         // Fails, because no matter how many
       &js.f.asBar().initialsequence);  // casts you add, bar still has a vptr!

换句话说,你可以自由地欺骗编译器(通过type-punning和reinterpret_cast),但这并不能使你的谎言成真。 ;)

另请参阅:XY problem.

答案 1 :(得分:0)

在OSX的XCode C ++ 11编译器选项中尝试过,似乎对我有用。当然,你可能想做“:: new(static_cast(&amp; f.m_storage))bar();”在foo的构造函数中,在foo的析构函数中调用它的析构函数。

答案 2 :(得分:0)

使用对齐数量时

1)建议使用 declspec(align(16))或__attribute ((aligned(16)))为类或结构指定对齐方式。当我不使用VS2010进行优化时,我遇到了一些错误。

2)我通常会避免重载新内容并使用您建议的展示位置运算符,例如

#include <new> // Remember this otherwise the placement operator is not defined
SomeClass* c = (SomeClass*) _mm_malloc(sizeof(SomeClass),16);
new c SomeClass(); // This is perfectly legal
// Some work
_mm_free(c);

3)一个好的经验法则是在结构或类的开头放置对齐的数量。这样编译器就不会在成员之间进行零填充,并对此发出警告。