У меня есть код, который я модифицирую, чтобы использовать allocator
вместо operator new
и operator delete
напрямую. Одна часть открытого интерфейса этого кода - возвращать не лысый указатель, а shared_ptr
(созданный из лысого указателя, блуждающего из new
.)
Я вижу в публичном контракте для распределителя несколько определений типов с именами pointer
, const_reference
и т. Д. Идея состоит в том, чтобы вместо прямого обращения к типам T *
я мог бы использовать pointer
, позволяя автору распределителя проскользнуть во что-то, кроме указателя C.
Но я, в свою очередь, оборачиваю обычный указатель в умный указатель, которому нужен честный указатель C (я думаю.) Если я попытаюсь изменить свой код на использование typedefs распределителя, возникнут ли у меня проблемы? Я еще не пробовал (так как нужно просто немного потрудиться), поэтому сначала спрашиваю ..
РЕДАКТИРОВАТЬ: Вот часть кода, который я хочу изменить (я не включил в первый раз, потому что это не очень дружелюбно.)
template<typename Injector, typename Iface, typename Allocator, typename Impl, typename A1>
class New<Injector, Iface, Allocator, Impl, Impl(A1)>: public Binding<Injector> {
public:
static Impl * provide(Injector const & injector) {
SAUCE_SHARED_PTR<A1> a1(injector.template provide<A1>());
return initializer(injector).template construct<Impl, SAUCE_SHARED_PTR<A1> >(a1);
}
static void dispose(Injector const & injector, Iface * iface) {
Impl * impl = static_cast<Impl *>(iface);
initializer(injector).destroy(impl);
}
};
// Elsewhere
template<typename Iface>
SAUCE_SHARED_PTR<Iface> provide() const {
Iface * provided = provideFromBinding<Iface>(
Module::template bindings<Injector_> );
SAUCE_SHARED_PTR<Iface> smartPointer;
smartPointer.reset(provided, deleter);
return smartPointer;
}
В частности, методы шаблонов construct
и destroy
, вызываемые в результате выражения initializer(injector)
, в настоящее время включают непосредственное использование new
и delete
. Я бы хотел использовать вместо него Allocator
и переключить их на размещение нового / явного уничтожения, чтобы сделать что-то вроде
template<typename Injector, typename Iface, typename Allocator, typename Impl, typename A1>
class New<Injector, Iface, Allocator, Impl, Impl(A1)>: public Binding<Injector> {
public:
static Impl * provide(Injector const & injector) {
SAUCE_SHARED_PTR<A1> a1(injector.template provide<A1>());
Allocator allocator;
Impl * impl = allocator.allocate(sizeof(Impl));
initializer(injector).template construct<Impl, SAUCE_SHARED_PTR<A1> >(impl, a1);
return impl;
}
static void dispose(Injector const & injector, Iface * iface) {
Allocator allocator;
Impl * impl = static_cast<Impl *>(iface);
initializer(injector).destroy(impl);
allocator.deallocate(impl, sizeof(Impl));
}
};
Вопрос заключается в том, должен ли я попытаться соблюдать typedefs распределителя? Похоже, что так и должно быть, иначе я неправильно использую распределитель (не говоря уже о том, что практически все они будут иметь "скучные" значения typedef.)
Я, конечно, могу подтолкнуть его, чтобы вернуть Allocator::pointer
вместо Impl *
, пока я не попытаюсь засунуть его в shared_ptr
. А может, там тоже все работает? Это мой вопрос. Возможно, кто-то, более знакомый со стандартом, чем я, мог бы сказать что-то вроде: «Пока Allocator::pointer
крякает как operator*
, и вы регистрируете пользовательский удалитель, у вас все будет хорошо».
РЕДАКТИРОВАТЬ: @bdonlan поднимает превосходную точку, что shared_ptr
шаблонируется на то, что будет Allocator::value_type
, а не Allocator::pointer
. Вместо этого он предположительно содержит Allocator::value_type *
внутри. Похоже, это отвечает на этот вопрос, за исключением того, что автор распределителя может решить реализовать operator Allocator::value_type *
в своих Allocator::pointer
таким образом, что даже при использовании преобразованного значения оно «все работает» в соответствии с какой-то конкретной заявленной семантикой.
Требует ли стандарт, чтобы это сделали авторы распределителя?
РЕДАКТИРОВАТЬ: См. относящиеся.