我正在研究类似std::function
对象的实现小缓冲区优化。
Boost实现boost::function
的小缓冲区,如下所示:
union function_buffer
{
mutable void* obj_ptr;
struct type_t {
const detail::sp_typeinfo* type;
bool const_qualified;
bool volatile_qualified;
} type;
mutable void (*func_ptr)();
struct bound_memfunc_ptr_t {
void (X::*memfunc_ptr)(int);
void* obj_ptr;
} bound_memfunc_ptr;
struct obj_ref_t {
mutable void* obj_ptr;
bool is_const_qualified;
bool is_volatile_qualified;
} obj_ref;
// To relax aliasing constraints
mutable char data;
};
并做了类似的事情:
new (reinterpret_cast<void*>(&out_buffer.data)) functor_type(*in_functor);
此外,C ++ 11提供std::aligned_union
和std::aligned_storage
which seems suitable for this。前者给出了一种类型:
适合用作任何对象的未初始化存储 大小最多为
的除数Len
,其对齐方式为Align
我很想使用类似的东西:
class MyFunction {
private:
typename std::aligned_storage<something>::type buffer;
MyFunctionVtable* vtable;
public:
template<class F>
MyFunction(F f)
{
static_assert(sizeof(F) <= sizeof(buffer) &&
alignof(F) <= alignof(buffer), "Type not suitable");
new (&buffer) F(std::move(f));
vtable = ...;
}
// [...]
};
这个(或者boost实现)是否会破坏类型别名规则?为什么?我倾向于认为存在会引发不端行为的陷阱。
作为参考,C ++标准中的注释给出了aligned_storage
的典型实现:
template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
typedef struct {
alignas(Alignment) unsigned char __data[Len];
} type;
};
看起来类似于sens中的boost版本,它们都依赖于char
来“启用”别名。
std::aligned_union<>::type
怎么样?使用未明确列出的类型是否安全?
答案 0 :(得分:2)
对于第一个近似值,当您使用一种类型写入存储位置并使用另一种类型读取时,会出现别名,并且这两种类型都不是窄字符类型(char
,{ {1}},signed char
)。
如果Boost实现在任何时候只有一个成员写入unsigned char
然后读取另一个成员,那么Boost实现是不安全的,除非其中一个成员是function_buffer
。 data
成员被注释data
的事实可能表明Boost开发人员认为他们可以欺骗编译器而不会注意到别名冲突。
您建议的// To relax aliasing constraints
或std::aligned_storage
解决方案很好,只要您的std::aligned_union
仅通过在您的展示位置 - 新表达式{{中写入时使用的类型进行读取1}},所以编写vtable
并将结果表达式用作指向类型为new (&buffer) F(std::move(f));
的对象的reinterpret_cast<F*>(&buffer)
类型的对象。
使用F*
可以放置任何类型较小且对齐要求较低的类型。使用static_assert进行显式化通常是个好主意:
F