我应该使用QScopedPointer还是std :: unique_ptr?

KcF*_*nMi 9 c++ qt c++11 qt5 c++14

我正在开始一个新项目,使用Qt5和QMAKE_CXXFLAGS += -std=c++1y.我不确定我是否应该更喜欢QScopedPointerstd::unique_ptr.

我读的地方QScopedPointer是不是很酷了.

是否QScopedPointer有任何功能unique_ptr没有?unique_ptr在更换时是否有任何我不想要的功能QScopedPointer?或相反亦然?

Yak*_*ont 12

QScopedPointer是严格弱,unique_ptr因为它不支持移动语义.

它的功能非常相似.

移动语义非常有用,并且意外地错误地使用它们来引起问题是极其罕见的.所以他们从无害到(更典型)有用.

关于您应该使用的唯一原因QScopedPointer是与现有代码库的互操作性; 甚至在那里,鉴于它们有多么相似,适配器将非常简单.

所以如果你不需要适应,请使用unique_ptr.


我现在讨论适应.

棘手的部分是第二个参数QScopedPointer.它非常粗略地对应于第二个参数unique_ptr.

unique_ptr有状态的删除者是允许的.在QScopedPointer他们没有.该

static void cleanup(T* pointer)
Run Code Online (Sandbox Code Playgroud)

对应于

void operator()(T* pointer)const
Run Code Online (Sandbox Code Playgroud)

unique_ptr一个漂亮的一对一的基础上.所以:

template<class QDelete>
struct std_deleter {
  template<class T>
  void operator()(T* target) const {
    QDelete::cleanup(target);
  }
};
Run Code Online (Sandbox Code Playgroud)

将Qt删除器映射到std删除器.另一种方式受限于删除者是无国籍的:

template<class Std_deleter>
struct Qt_deleter {
  template<class T>
  static void cleanup(T* target) {
    static_assert(std::is_empty<Std_deleter>{}, "Only works with stateless deleters");
    Std_deleter{}(target);
  }
};
Run Code Online (Sandbox Code Playgroud)

我们现在可以转换:

template<class T, class D>
QScopedPointer<T, Qt_deleter<D>>
to_qt( std::unique_ptr<T, D>&& src ) {
  return src.release();
}
template<class T, class D>
QScopedPointer<T, Qt_deleter<D>>
to_qt( std::unique_ptr<T[], D>&& src ) {
  return src.release();
}
template<class T>
QScopedPointer<T>
to_qt( std::unique_ptr<T>&& src ) {
  return src.release();
}
template<class T>
QScopedPointer<T, QScopedPointerArrayDeleter>
to_qt( std::unique_ptr<T[]>&& src ) {
  return src.release();
}
template<
  class T, class D, class R=std::unique_ptr<T, std_deleter<D> >
>
to_std( QScopedPointer<T, D>&& src ) {
  return R(src.take()); // must be explicit
}
template<class T, class R=std::unique_ptr<T>>
to_std( QScopedPointer<T>&& src ) {
  return R(src.take()); // must be explicit
}
template<class T, class R=std::unique_ptr<T[]>>
to_std( QScopedPointer<T,QScopedPointerArrayDeleter >&& src ) {
  return R(src.take()); // must be explicit
}
Run Code Online (Sandbox Code Playgroud)

它涵盖了你使用的唯一原因QScopedPointer.有一些极端情况 - 默认删除器QScopedPointer应转换为默认值std::unique_ptr,反之亦然.

数组删除QScopedPointer应转换为a unique_ptr<T[]>,反之亦然.

在其他情况下,我只是包装删除器.理论上,一个非常奇特的技巧是注意到传入的删除器是否已经被包裹并反转包装,但如果你的代码执行了那么多次往返,那么可能已经出现了问题.

  • "与现有代码库的互操作性"我不称之为"互操作性".`QScopedPointer`实际上是用于C++ 98代码库(这就是为什么`QScopedPointer`没有移动语义).鉴于你甚至无法移动它,它通常只是一个实现辅助工具,你不会在任何API中看到它(不像`unique_ptr`).Qt项目故意不会让`QScopedPointer`更好 - 你已经有了它,它是`unique_ptr`.在新的,支持C++ 11的项目中使用`unique_ptr`,而不是`QScopedPointer`. (4认同)