2014-01-15 2 views
1

У меня есть фабричный шаблон с использованием новых возможностей C++ 11. Для этого в реестре зарегистрирована функция std ::. Теперь я пытаюсь реализовать экземплярную часть. Сейчас это реализовано так:вызов std: make_shared через std :: function

std::map<uint32_t, std::function<Class*()>>::iterator it = m_creators.find(id); 
if(it != m_creators.end()) 
{ 
    return std::shared_ptr<Class>((it->second)()); 
} 

Проблема заключается в том, что это, очевидно, не спасает исключения, и я пытаюсь заменить станд :: shared_ptr вызов с эквивалентным стандом :: make_shared вызова. Std :: function - это функция create, которая вызывает только конструктор подкласса Object. Проблема в том, что я понятия не имею, как использовать std :: function вместо вызова конструктора в std :: make shared. Возможно ли это?

+4

* Почему вы хотите использовать 'make_shared', когда ваше решение должно работать нормально? Если вы видите, например. [эта ссылка] (http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared) 'std :: make_shared' больше не является исключением. –

+0

Почему это не безопасно? –

+0

@JoachimPileborg, чтобы быть справедливым "* why *", именно поэтому он задает вопрос и, возможно, может сделать с вашим опытом :) –

ответ

1

Я бы сделал функцию std :: function возвращать shared_ptr, а не голый указатель. Затем вы можете использовать make_shared внутри функции std ::.

typedef std::map<uint32_t, std::function<std::shared_ptr<Class>()>> CreatorMap; 
CreatorMap::iterator it = m_creators.find(id); 
if(it != m_creators.end()) 
{ 
    return (it->second)(); 
} 

// example of a creator 

struct SomeCreator{ 
public: 
    std::shared_ptr<Class> operator()(){ 
     return std::make_shared<Class>(); 
    } 
} 

это также обеспечивает большую гибкость, позволяющую фабрике использовать пользовательский дебетер.

+0

Спасибо, почему я не придумал это. Это просто. – evotion

1

Код, который у вас есть, не является исключением небезопасным. Конструктор shared_ptr, который принимает указатель, вызовет delete на управляемом указателе, если во время инициализации возникает исключение.

С N3797, §20.8.2.2.1/7

template<class Y> explicit shared_ptr(Y* p);
...
безопасности Исключение: Если исключение, delete p называется.

Если это заставляет Вас чувствовать себя лучше, вы могли бы изменить map типа для

std::map<uint32_t, std::function<std::unique_ptr<Class>()>> 

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

+0

класс вызывается внутри перегруженного оператора вызова функции фабрики std :: function, а что, если что-то между новым и возвратным? скорее всего, но возможно. – odinthenerd

+0

@ PorkyBrain Ну, это будет ошибка в написании заводской функции. Во всяком случае, мои редакционные адреса выходят. – Praetorian

+0

, хотя это не задано OP, это все равно не позволит фабрике добавлять пользовательский удаляющий элемент в общий указатель, чтобы не было тривиально разрушаемых типов или пользовательских распределителей, которым нужен пользовательский делектор. – odinthenerd

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