在C++11
中没有make_unique
(不能使用C++14
),虽然可以很快被人嘲笑(已经有大量答案提示这样的事情) :
template< typename T, typename ... Args >
std::unique_ptr< T > my_make_unique (Args && ... args) {
return { new T( std::forward< Args >( args )... ) };
}
如果期望的结果是new
/ delete
在typename T
上调用,则可以。在我的情况下,这不是因为我压倒全球new
/ delete
,内部将(方便)使用unique_ptr
。所以相反,我正在使用malloc
和各种包装器&amp;基于malloc
的分配器使STL容器在使用站点没有额外膨胀的情况下工作。我一直在用这种方法做得很好,直到有例外......
基于this question到目前为止的答案,我将此作为一种可能的通用解决方案:
template< typename T >
struct destroy_free {
void operator() (void * p) {
if ( !p ) return;
static_cast< T* >( p )->~T();
free( p );
}
};
template< typename T, typename ... Args >
auto malloc_make_unique (Args && ... args) -> std::unique_ptr< T, destroy_free< T > > {
if ( auto ptr = malloc( sizeof(T) ) )
return { new ( ptr ) T( std::forward< Args >( args )... ) };
return { nullptr }; // global new would throw bad_alloc here.
}
这似乎没问题,但是new (ptr) T(...)
与new T(...)
相比,make_unique
的工作原理完全忽略了异常处理,以及它如何影响std::bad_alloc
的任何版本,尤其是在使用自定义分配方法。
首先,我知道抛出new
是不明智的,但我相信这里应用最少惊喜的原则,并且可以原谅nullptr
会做什么(即分配时抛出)失败而不是返回return { nullptr }
)。这引出了两个问题。
1。将throw std::bad_alloc()
替换为new T(...)
2。要正确复制template< typename T, typename ... Args >
auto malloc_make_unique_v2 (Args && ... args) -> std::unique_ptr< T, destroy_free< T > > {
if ( auto ptr = malloc( sizeof(T) ) ) try {
return { new ( ptr ) T( std::forward< Args >( args )... ) };
} catch( ... ) { // catch constructor exceptions
// assumed: memory allocated but object not constructed
free( ptr ); // release memory, object was not constructed?
throw; // propagate whatever the exception was during construction?
}
throw std::bad_alloc(); // no memory allocated, throw bad_alloc?
}
的行为,如果构造函数抛出然后需要捕获异常,那么可以立即释放内存并然后重新抛出构造函数异常? < / p>
假设两者都是,下面是正确处理情况还是还有其他需要考虑的事情?
0,102,5.0
1,101,5.0
1,102,5.0
编辑 - 请注意我为了简单而忽略了对齐。
答案 0 :(得分:0)
假设两者都是,下面是正确处理情况还是还有其他需要考虑的事情?
对我好看。
有Python Demo创建shared_ptr与自定义分配器分配的对象内存。你所做的基本上是allocate_unique
,它在标准的c ++中是不存在的(也许是)。也许您可以创建使用malloc / free的自定义分配器,然后实现自己的std::allocate_shared(如果没有)和allocate_unique
。