Обобщая общие указатели и QSharedPointer::data() против shared_ptr::get()?
Я сделал библиотеку Qt, которая построена на давних абстракциях, таких как QSharedDataPointer
а также QSharedData
, Поэтому, когда мне нужен был обычный разделяемый указатель, имело смысл QSharedPointer
для согласованности.
Я сейчас использую это в проекте C++11. Чтобы сделать код более стандартным, я переключаюсь на shared_ptr
для всех своих локальных подсистем.
Зависимость C++11 внутри самой библиотеки не обязательно желательна, поэтому казалось, что вы должны быть в состоянии выбрать, какой тип общего указателя вы хотите использовать. В качестве первого шага, чтобы двигаться вперед, я попробовал этот метод, предложенный в Гибкость псевдонима шаблона в C++ 0x (по общему признанию, сама зависимость C++11, но я мог бы использовать препроцессор через флаг компилятора в не-C++11 строит)
#if THINKERQT_USE_STD_SHARED_PTR
#include <memory>
template<class T>
using shared_ptr_type = std::shared_ptr<T>;
#else
#include <QSharedPointer>
template<class T>
using shared_ptr_type = QSharedPtr<T>;
#endif
К сожалению, классы указателей выбрали разные имена для методов. Примечательно, что доступ к содержащемуся указателю осуществляется .get()
в shared_ptr и .data()
в QSharedPointer.
Я собирался сделать экстрактор, какой-то shared_ptr_type_get<>
но затем заметил, что можно эффективно добиться того же (в тех случаях, когда содержащийся указатель не является нулевым, и я могу проверить на нулевое значение с помощью логического приведения) с помощью:
&(*ptr)
Если вы читаете код, это немного замедляет работу, и некоторые вещи, которые кто-то может попытаться оптимизировать (затем быстро понять, что это не сработает). Но кроме фактора WTF, это кажется достаточно безобидным... не так ли?
1 ответ
Я использую это и в своем проекте, и в этом нет ничего плохого, кроме читабельности, как вы уже заметили. И, как отметил Майк Сеймур, вы всегда должны проверять, что ptr не является нулевым указателем.
Я использую следующие идиомы в большинстве случаев:
if( shared_ptr_type ptr = funcReturnsSharedPtr() )
{
funcAcceptsRawPtr(&*ptr);
}
В значительной степени гарантируется, что он будет компилироваться и функционировать правильно независимо от того, какой тип общего указателя вы используете shared_ptr_type
поскольку любой разумный класс общего указателя будет перегружен operator*
,