2016-10-31 1 views
5

Я начинаю новый проект, используя Qt5 и QMAKE_CXXFLAGS += -std=c++1y. Я не уверен, предпочитаю ли я QScopedPointer или std::unique_ptr.Должен ли я использовать QScopedPointer или std :: unique_ptr?

Я прочитал somewhere, что QScopedPointer больше не круто.

Есть QScopedPointer Есть ли функции unique_ptr Отсутствует? Есть ли функции unique_ptr, которые я бы не захотел при замене QScopedPointer? Или наоборот?

+3

Я бы использовал 'std :: unique_ptr'. – NathanOliver

+0

Я могу сказать, что я сократил использование интеллектуальных указателей Qt и перешел на использование 'std :: shared_ptr' и' std :: unique_ptr'. – drescherjm

+2

Всякий раз, когда у меня есть выбор между классом из стандартной библиотеки и другим, я всегда выбираю стандартную библиотеку, если нет веской причины. Одной из таких убедительных причин было бы, если вам нужна совместимость с кодом, который использует другой тип. –

ответ

5

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[]> и наоборот.

В других случаях я просто завершаю машину. Теоретически, действительно фантазийным фокусом было бы заметить, что входящий делектор уже был завернут и отменил обертывание, но если ваш код делает много круговых поездок, возможно, уже что-то не так.

+3

«Совместимость с существующими базами кода» Я бы не назвал это «интероперабельностью». 'QScopedPointer' действительно предназначен для кодовых баз C++ 98 (поэтому' QScopedPointer' не имеет семантики перемещения). Учитывая, что вы даже не можете его перемещать, это, как правило, просто помощь в реализации, и вы не видите, чтобы это отображалось в каких-либо API (в отличие от 'unique_ptr'). И проект Qt намеренно не делает 'QScopedPointer' лучше - вы уже получили это, это' unique_ptr'. Используйте 'unique_ptr', а не' QScopedPointer', в новых проектах с поддержкой C++ 11. – peppe

+0

@peppe представляет собой 10-миллионную линейную базу кода, которая «возвращает» QScopedPointer через ссылку и принимает параметры с помощью QScopedPointer ref и cref повсюду, некоторые из его устаревших библиотек, для которых у вас больше нет источника, но должны сохранять функциональность и temble. Я хочу сказать, что даже если у вас есть этот взломанный hellscape существующей базы кода, не используйте QScopedPointer. Используйте 'to_qt' и' to_std'. – Yakk

0

Несмотря на то, что основная цель обоих классов схожа, существует одна важная разница между этими двумя, которая заставляет вас принять какое-то деловое решение.

QScopedPointer не имеет оператора присваивания. Где в качестве std :: unique_ptr есть оператор присваивания.

Если вы хотите быть строгим в своем объекте/управлении QT и не хотите, чтобы назначение выполнялось QScopedPointer.

+2

'const unique_ptr' также не имеет оператора присваивания. –

+1

Да. Но ОП не сказал, что const. – Naidu

1

Почему вы используете что-то не из стандартной библиотеки по сравнению с чем-то из стандартной библиотеки?

Для меня есть только одна причина, по которой любой хороший программист мог бы это сделать: если внешняя библиотека предоставляет то, что стандартная библиотека не предоставляет. Это так?

Рассмотрите переносимость и обновления своей программы в будущем, а затем сделайте это решение.

Смежные вопросы