Обобщение общих указателей и QSharedPointer::data() против shared_ptr::get()?

Я создал библиотеку Qt, построенную на устаревших абстракциях, таких как QSharedDataPointer и QSharedData. Поэтому, когда мне понадобился обычный общий указатель, имело смысл использовать QSharedPointer для согласованности.

Сейчас я использую это в проекте С++ 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, это кажется достаточно безобидным... не так ли?


person HostileFork says dont trust SE    schedule 22.06.2012    source источник
comment
Педантично, &*ptr дает неопределенное поведение, если указатель имеет значение null.   -  person Mike Seymour    schedule 22.06.2012
comment
@MikeSeymour Ага. Но, как я уже сказал, вы можете static_cast<bool> и QSharedPointer, и shared_ptr проверить на нуль, если вам нужно; у них есть одинаковая поддержка для этого.   -  person HostileFork says dont trust SE    schedule 23.06.2012


Ответы (1)


Я также использую это в своем проекте, и в этом нет ничего плохого, кроме удобочитаемости, как вы уже заметили. И, как указал Майк Сеймур, вы всегда должны сначала проверять, что ptr не является нулевым указателем.

В большинстве случаев я использую следующую идиому:

if( shared_ptr_type ptr = funcReturnsSharedPtr() )
{
    funcAcceptsRawPtr(&*ptr);
}

Практически гарантировано, что это будет компилироваться и работать правильно, независимо от того, какой тип общего указателя вы используете для shared_ptr_type, поскольку любой разумный класс общего указателя будет перегружать operator*.

person smerlin    schedule 22.06.2012
comment
+1 Рад видеть, что я не один такой. (Мне нравится ссылаться на такие вопросы внутри кода на случай, если кто-то прочитает и решит Почему он это сделал?) Но из-за моих собственных идиом я бы использовал boost::optional< shared_ptr<T> > в тех интерфейсах, где ноль возможен/значим. Это позволяет системе типов участвовать во время компиляции, чтобы убедиться, что все, кому нужно проверить отсутствие указателя, делают это. Это хорошо работает для меня, хотя я называю свои подпрограммы такими вещами, как funcReturnsSharedPtrMaybeNull, если я нахожусь в контексте без дополнительных разрешений и хочу привлечь внимание к потенциальным нулям. - person HostileFork says dont trust SE; 23.06.2012