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 deleter для детонатора std. Другой путь ограничен Deleter будучи лицом без гражданства:
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
и наоборот.
Массив delete QScopedPointer
должен быть преобразован в unique_ptr<T[]>
и наоборот.
В других случаях я просто завершаю машину. Теоретически, действительно фантазийным фокусом было бы заметить, что входящий делектор уже был завернут и отменил обертывание, но если ваш код делает много круговых поездок, возможно, уже что-то не так.
Я бы использовал 'std :: unique_ptr'. – NathanOliver
Я могу сказать, что я сократил использование интеллектуальных указателей Qt и перешел на использование 'std :: shared_ptr' и' std :: unique_ptr'. – drescherjm
Всякий раз, когда у меня есть выбор между классом из стандартной библиотеки и другим, я всегда выбираю стандартную библиотеку, если нет веской причины. Одной из таких убедительных причин было бы, если вам нужна совместимость с кодом, который использует другой тип. –