reinterpret_cast
在构造函数中,如果我发现对象的大小小于联合,我将其直接存储在与位置新的位置并丢弃新位置的返回值。
template<typename Signature>
class UniqueFunction;
template<typename Ret, typename... Args>
class UniqueFunction<Ret( Args... )> {
struct AnyFn {
virtual ~AnyFn() noexcept = default;
virtual Ret operator()( Args... args ) = 0;
};
template<typename Fn>
struct FnContainer : public AnyFn {
Fn fntor_;
FnContainer( Fn fntor ) : fntor_ { std::move( fntor ) } {}
FnContainer( const FnContainer& ) = delete;
FnContainer& operator=( const FnContainer& ) & = delete;
virtual ~FnContainer() noexcept = default;
Ret operator()( Args... args ) override { return fntor_( std::forward<Args>( args )... ); }
};
union {
typename std::add_pointer<Ret( Args... )>::type fptr_;
AnyFn* ftor_;
} data_; // The union is here.
// Tag that identifies the type of data currently stored in the union.
enum class Tag : std::uint8_t { None, Fptr, FtorInline, FtorDync } tag_;
// other methods...
};
在这种情况下,我将重新解释联合的地址为template<typename F>
UniqueFunction( F functor )
{
if ( sizeof( FnContainer<F> <= sizeof data_ ) {
new ( &data_ ) FnContainer<F>( std::move( functor ) );
tag_ = Tag::FtorInline;
} else {
data_.ftor_ = new FnContainer<F>( std::move( functor ) );
tag_ = Tag::FtorDync;
}
通过
AnyFn*
尝试使用基本指针访问该区域上存储的派生对象。
reinterpret_cast
我知道在C ++标准中有一条规则称为严格的别名,因此我怀疑我的优化违反了标准并引起某种UB。不过,我不太确定,因为该代码在测试中效果很好。
在线测试是
。 问题是:这是UB吗?如果是这样,我是否有另一种方法可以实现我想要的小物体优化?
放置新呼叫不是UB。但是它结束了联合对象的寿命,因为它重用了联合对象所占据的存储。请参阅
[basic.life]/2.5。
if ( tag_ == Tag::FtorInline ) {
// When I'm trying to deconstruct it, I do this:
// reinterpret_cast<AnyFn*>( &data_ )->~AnyFn();
// Other cases, I do this:
( *reinterpret_cast<AnyFn*>( &data_ ) );
}
成为指向不在其寿命内的对象的指针。
&data_
不会产生指向reinterpret_cast
对象的指针。它等同于a
AnyFn
到
static_cast
,然后是第二个void*
到
static_cast
。第一个演员很好。当该对象与原始Pointee(Dead Union对象)(死去的联合对象)
pointer-interconvertible时,第二个仅将实际生成指向
AnyFn*
。这种情况将无法满足。通过结果指针访问将是UB。 有时可以通过将铸件的结果传递到
AnyFn
来获得指向AnyFn
基类子对象的指针。但是,只有当
std::launder
基类子对象实际上位于
AnyFn
存储的开头时,这才能起作用。无法保证这种情况。要实施小对象优化,建议将一个或
data_
的数组作为联盟成员之一。然后将小物体放置在该数组中。位置返回的指针新的新成员存储,用于访问创建的对象。