考虑以下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
这合法吗?我可以用它来欺骗我对标准布局类型的限制吗?
答案 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)一个好的经验法则是在结构或类的开头放置对齐的数量。这样编译器就不会在成员之间进行零填充,并对此发出警告。