异常感知的malloc版本的make_unique

时间:2017-04-18 12:31:10

标签: c++11 exception-handling malloc unique-ptr placement-new

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 / deletetypename 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

编辑 - 请注意我为了简单而忽略了对齐。

1 个答案:

答案 0 :(得分:0)

  

假设两者都是,下面是正确处理情况还是还有其他需要考虑的事情?

对我好看。

Python Demo创建shared_ptr与自定义分配器分配的对象内存。你所做的基本上是allocate_unique,它在标准的c ++中是不存在的(也许是)。也许您可以创建使用malloc / free的自定义分配器,然后实现自己的std::allocate_shared(如果没有)和allocate_unique