智能替换'new []'到make_unique

时间:2016-06-07 11:44:36

标签: c++ c++11 c++14 unique-ptr

我正在替换像:

这样的陈述
auto pszOutBuffer = new char[dwSize];

ReadDataFromHttp(pszOutBuffer, dwSize);
if(dwSize>100)
    ParseHttpData(pszOutBuffer);
    ...
delete []pszOutBuffer;

TO:

auto OutBufferPtr = make_unique<char[]>(dwSize);
auto pszOutBuffer = OutBufferPtr.get();

ReadDataFromHttp(pszOutBuffer, dwSize);
if(dwSize>100)
    ParseHttpData(pszOutBuffer);
...

这样我就可以利用智能指针unique_ptr。我希望保持变量pszOutBuffer不变,因此Git提交中的更改变少,并且不需要重复unique_ptr.get()

使这个变得简单,阅读不那么冗长;我编写一个宏MAKE_UNIQUE_PTR(type,size),它将是一个单独的语句(两个,如上所示)。但是,这样的宏将不能像{1}}一样unqiue_ptr,而在

中也是如此
pszOutBuffer

我可能会考虑编写一个函数模板,但是......如何在函数(auto pszOutBuffer = MAKE_UNIQUE_PTR(char, dwSize); )之后保持unique_ptr返回?

修改

使用此假设的宏/函数,代码将只是:

MAKE_UNIQUE_PTR

具有以下优势:

  • auto pszOutBuffer = MAKE_UNIQUE_PTR(char, dwSize); ReadDataFromHttp(pszOutBuffer, dwSize); if(dwSize>100) ParseHttpData(pszOutBuffer); ... 仍然控制缓冲区的生命周期。
  • 原始样式指针仍然存在,而不会将它们归为unique_ptr次调用。
  • 因此可以安全地从多个代码路径中删除unique_ptr::get()个调用。

请注意,第一个代码是我手头的代码。没有宏,没有delete[] - 只有遗留代码unique_ptrnew。是的......那些匈牙利符号变量。

3 个答案:

答案 0 :(得分:4)

不幸的是,由于original proposal中显示的原因,我们不支持std::make_unique<T[N]>()。但是,没有什么可以阻止您为数组(例如make_unique)制作自己的make_unique_array,如下所示:

template<typename T>
std::enable_if_t<std::is_array<T>::value, std::unique_ptr<T>>
make_unique_array(std::size_t const n) {
  using RT = std::remove_extent_t<T>;
  return std::unique_ptr<T>(new RT[n]);
} 

答案 1 :(得分:1)

由于您已经在使用宏,因此可以编写一个可以创建两者的宏。这很丑陋,但确实有它的作用。

#define SmartMacro(pszOutBuffer, dwSize) \
                     auto pszOutBuffer##ptr = make_unique<char[]>(dwSize); \
                     auto pszOutBuffer = pszOutBuffer##ptr.get(); \
                     memset(pszOutBuffer, 0, dwSize);

// Usage
SmartMacro(buffer, 10);
// 'buffer' is the raw pointer
// 'bufferptr' is the unique pointer

答案 2 :(得分:1)

template<class T, class D>
struct smart_unique:std::unique_ptr<T,D> {
  using std::unique_ptr<T,D>::unique_ptr;
  operator T*()const{return this->get();}
  operator T const*()const{return this->get();}
};
template<class T, class D>
struct make_smart_unique_t {
  template<class...Ts>
  smart_unique<T, D> operator()(Ts&&...ts)const{
    return smart_unique<T,D>( new T(std::forward<Ts>(ts)...); );
  }
  template<class T0, class...Ts>
  smart_unique<T, D> operator()(std::initializer_list<T0> il, Ts&&...ts)const{
    return smart_unique<T,D>( new T(il, std::forward<Ts>(ts)...); );
  }
};
template<class T, class D>
struct make_smart_unique_t<T[], D> {
  smart_unique<T[], D> operator[](std::size_t N)const{
    return smart_unique<T[],D>( new T[N]; );
  }
  template<class...Ts>
  smart_unique<T[], D> operator()(Ts&&...ts)const{
    return smart_unique<T[],D>( new T[sizeof...(Ts)]{std::forward<Ts>(ts)...}; );
  }
};
template<class T, class D=std::default_delete<T>>
constexpr make_smart_unique_t<T,D> make_smart_unique{};

这应该支持:

auto pszOutBuffer = make_smart_unique<char[]>[dwSize];

ReadDataFromHttp(pszOutBuffer, dwSize);
if(dwSize>100)
  ParseHttpData(pszOutBuffer);

以及:

auto pszDataBuffer = make_smart_unique<int[]>(1,2,3,4,5);

auto pszDataBuffer = make_smart_unique<int>();

不需要宏观魔法。

此处的设计很简单:make_smart_unique<scalar>make_unique类似,但它会返回smart_unique(隐式转换为T*:非常小心!)< / p>

make_smart_unique<Array[]>有两种不同的方式来调用它。使用[N]创建一个传入大小的数组:使用(args...)它创建一个元素数量大小的数组,并从每个arg构造每个元素。