Что-то не так в приведении из пустого указателя (для создания общего хранилища)?

Я пытаюсь создать общий класс хранения в C ++. Если вы посмотрите на код ниже, я хочу хранить карты string / AnyType и получить к ним доступ.

  class StoresTestC
{
public:
template < class SettingsType >
std::map< std::string, SettingsType >* getStore(std::string const&);
private:
std::map< std::string, void* > stores_;
};

template < class SettingsType >
std::map< std::string, SettingsType >* StoresTestC::getStore(std::string const& name)
{
if (stores_.count(name) > 0)
{
void* temp = this->stores_[name];
return (std::map< std::string, SettingsType >*)(temp);
}
else
{
std::map< std::string, SettingsType > * result = new std::map< std::string, SettingsType > ();
this->stores_[name] = result;
return result;
}
}

В этом я вижу две очевидные опасности:

  1. Если я назову это с неправильным SettingsType / name Я назову неправильный актерский состав, который, насколько я знаю (я могу ошибаться), приведет к неопределенному поведению.

  2. Это создаст утечку памяти, но у меня есть решение для этого (которое было слишком долго, чтобы быть раскрытым здесь).

Есть ли что-то еще, что может пойти не так, и вы можете предвидеть?

0

Решение

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

ОК, вам все еще нужна эта возможность?

использование std::map<std::string, boost::any> где boost::any всегда map тип. Затем, когда вы используете any_cast или какой-либо механизм, чтобы вернуть предмет, вы гарантированно, что это правильный тип или он бросает, так что вы никогда не рискуете неопределенным поведением. Кроме того, так как any по значению у вас нет возможной утечки памяти.

Следует также отметить, что в вашем оригинальном решении, если вы используете shared_ptr<void*> было бы помнить, как удалить исходный тип, хранящийся в этом shared_ptr таким образом устраняя утечку памяти, которую вы упомянули.

РЕДАКТИРОВАТЬ: Я не вижу никаких других очевидных технических проблем с чем-то вроде этого. Однако обратите внимание, что наличие такой карты возможно / может вызвать познавательный («гроккинг») проблемы для будущих сопровождающих, и это несколько увеличивает сложность кода.

2

Другие решения

Да, вы правы в своих сомнениях по поводу пункта 1 (пункт 2 должен быть решаем, как вы упомянули, но подумайте о том, что деструкторы содержащихся в них карт должны называться правильно).

Я не отпущу такой интерфейс в дикую природу, не предоставив простой механизм, за которым следят клиенты SettingsType и std::string Представление ‘typename’ в синхронизации. Простая опечатка может все испортить. я думаю что boost::any будет просто выражать это с исключением, как только вы попытаетесь привести значение к желаемому / ожидаемому типу результата.

Зачем тебе std::string представление здесь вообще? Если вы используете RTTI, например, вы можете скрыть ключ, используемый для stores_ с помощью typeid(),

1

Так как вам все равно нужно передать тип в качестве параметра шаблона, чтобы получить карту, нужно ли иметь только одну карту для каждого типа?

namespace StoresTest {
template<typename T>
struct MapStruct {
static std::map<std::string, T> the_map;
};

template<typename T> std::map<std::string, T> MapStruct<T>::the_map;

template<typename T>
inline std::map<std::string, T>& getStore()
{ return MapStruct<T>::the_map; }
}

Тогда, например, вы можете получить карту с типом значения Foo при выполнении

std::map<std::string, Foo>& foo_map = StoresTest::getStore<Foo>();

Вам больше не нужен string назвать тип, но это может быть добавлено, если у вас есть другие причины, чтобы хотеть его.

0
По вопросам рекламы [email protected]