我正在使用Qt5和QMAKE_CXXFLAGS += -std=c++1y
开始一个新项目。我不确定是否应该选择QScopedPointer
或std::unique_ptr
。
我读somewhere QScopedPointer
不再那么酷了。
QScopedPointer
是否有unique_ptr
缺少的功能?在替换unique_ptr
时,是否有QScopedPointer
的任何我不想要的功能?反之亦然?
答案 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进行赋值。