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

时间:2016-10-31 16:27:32

标签: c++ qt c++11 qt5 c++14

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

我读somewhere QScopedPointer不再那么酷了。

QScopedPointer是否有unique_ptr缺少的功能?在替换unique_ptr时,是否有QScopedPointer的任何我不想要的功能?反之亦然?

3 个答案:

答案 0 :(得分:11)

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

其功能非常相似。

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

关于使用QScopedPointer的唯一原因是与现有代码库的互操作性;即使在那里,考虑到它们有多么相似,适配器也很容易。

因此,如果您不需要进行调整,请使用unique_ptr

我现在讨论适应。

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

unique_ptr允许有状态的删除者。在QScopedPointer他们不是。在

static void cleanup(T* pointer)

对应

void operator()(T* pointer)const

unique_ptr中以一对一的方式进行。所以:

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

将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);
  }
};

我们现在可以转换:

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
}

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

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

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

答案 1 :(得分:1)

为什么你会使用非标准库中的东西与标准库中的东西相比?

对我而言,任何优秀的程序员都会这样做的原因只有一个:如果外部库提供标准库不提供的东西。是这样的吗?

考虑您的程序的可移植性和未来的更新,然后做出决定。

答案 2 :(得分:0)

尽管两个班级的主要意图相似,但这两个班级之间的一个重要区别是让你做出一些商业决策。

QScopedPointer没有赋值运算符。其中std :: unique_ptr具有赋值运算符。

如果你想对你的QT对象/控件严格要求并且不希望使用QScopedPointer进行赋值。