struct invoker {
void invoke() {}
};
struct type {
void register(const char *api) {
shared_ptr<invoker> p = std::make_shared<invoker>();
map.emplace(api, std::move(p));
}
void invoke(const char *api) {
auto it = map.find(api);
if ( it == map.end() ) return;
it->second->invoke();
}
private:
std::map<const char*, shared_ptr<invoker>> map;
};
тут type::register() зовется единожды при запуске программы, но а type::invoke() множество раз.
сейчас, похожий код хранит в мапе std::string, но для вызова invoke() мне доступен только const char*(приходит из сети), и из него приходится постоянно создавать временный std::string, только для вызова. вот от этого и хочу избавиться.
ключи для мапа могут быть только си-строками, ибо должны быть человекочитаемыми.
погугли про использование указателя для мапы, говорят, что достаточно указать свой компаратор мапе. есть ли еще какие-то "тонкости"?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
в принципе, не так страшно хранить с мапе std::string, т.е. можно оставить как есть. но хочется избавиться от временной std::string, т.е. чтоб была возможность сказать мапе, чтоб сравнивала std::string и const char*.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
X>погугли про использование указателя для мапы, говорят, что достаточно указать свой компаратор мапе. есть ли еще какие-то "тонкости"?
Только то, что ты сам должен гарантировать, что ключи будут жить достаточно долго. То есть, что указатели из map должны ссылаться на валидные строки всё время жизни map.
X>в принципе, не так страшно хранить с мапе std::string, т.е. можно оставить как есть. но хочется избавиться от временной std::string, т.е. чтоб была возможность сказать мапе, чтоб сравнивала std::string и const char*.
Так в C++ есть же прозрачные компараторы:
Можно рассмотреть вариант хранения вместо стринга std::array<char, MAX123>, если под задачу подходит. Если MAX123 не слишком велик, и хочется избавиться от сложности внутреннего представления std::string.
Здравствуйте, niXman, Вы писали:
X>сейчас, похожий код хранит в мапе std::string, но для вызова invoke() мне доступен только const char*(приходит из сети), и из него приходится постоянно создавать временный std::string, только для вызова. вот от этого и хочу избавиться. X>ключи для мапа могут быть только си-строками, ибо должны быть человекочитаемыми.
Ключ должен быть скопирован в мапу для хранения. Ты гарантируешь, что строка по твоему указателю const char* будут сохраняться в памяти всё время жизни соответствующей пары значений?
А во временном std::string для вызова нет особо плохого, по крайней мере в реализациях, где там отдельный буфер со счётчиком использования — как минимум так в GCC STL.
Здравствуйте, netch80, Вы писали:
N>Ключ должен быть скопирован в мапу для хранения. Ты гарантируешь, что строка по твоему указателю const char* будут сохраняться в памяти всё время жизни соответствующей пары значений?
N>А во временном std::string для вызова нет особо плохого, по крайней мере в реализациях, где там отдельный буфер со счётчиком использования — как минимум так в GCC STL.
строки со счетчиком уже не стандартны.
гсс их вроде выпиливали.
Здравствуйте, netch80, Вы писали:
N>А во временном std::string для вызова нет особо плохого, по крайней мере в реализациях, где там отдельный буфер со счётчиком использования — как минимум так в GCC STL.
Начиная с gcc 5.1 в тамошнем STL std::basic_string уже не использует COW, поскольку COW не вписывается требования стандарта C++11 для std::basic_string.
W>>Теперь временные строки при поиске const char* создаваться не будут.
SVZ>(правда зачем тут менять компаратор)?
Так std::less<> и std::less<std::string> — разные вещи. Если не указывать, то по умолчанию будет использоваться второй, который будет создавать экземпляры std::string даже при использовании шаблонной версии метода find.
Здравствуйте, Masterspline, Вы писали:
M>std::map::find() в качестве аргумента принимает Key& (а это std::string) и не факт, что оптимизатор сможет удалить создание временной строки.
В std::map есть несколько методов find. Как указанный вами с аргументом const Key&, так и шаблонный
template< class K > iterator find( const K& x );
который будет выбираться для const char*.
И при прозрачном компараторе он внутри себя не будет конструировать std::string, а напрямую будет сравнивать std::string с const char*
struct invoker {
void invoke() {}
};
struct type {
void register(const char *api) {
shared_ptr<invoker> p = std::make_shared<invoker>();
map.emplace(api, std::move(p));
}
void invoke(const char *api) {
auto it = map.find(api);
if ( it == map.end() ) return;
it->>second->invoke();
}
private:
std::map<const char*, shared_ptr<invoker>> map;
};
X>тут type::register() зовется единожды при запуске программы, но а type::invoke() множество раз. X>сейчас, похожий код хранит в мапе std::string, но для вызова invoke() мне доступен только const char*(приходит из сети), и из него приходится постоянно создавать временный std::string, только для вызова. вот от этого и хочу избавиться.
Если есть гарантия, что аргумент register() живет дольше, чем существует map, то достаточно задать компаратор для map. Если же такой гарантии нет, то я бы сделал кроме
W>В std::map есть несколько методов find. Как указанный вами с аргументом const Key&, так и шаблонный
W>template< class K > iterator find( const K& x );
W>который будет выбираться для const char*.
W>И при прозрачном компараторе он внутри себя не будет конструировать std::string, а напрямую будет сравнивать std::string с const char*
Да, действительно есть. Похоже начиная с c++14 достаточно в map задать компаратор, причем подойдет стандартный std::less<> (без типа).
Здравствуйте, niXman, Вы писали:
X>тут type::register() зовется единожды при запуске программы, но а type::invoke() множество раз.
Используй std::vector<std::string>, отсортируй после всех register, но перед первым invoke, ищи через свободную функцию std::lower_bound, передавая свой компазатор:
Здравствуйте, watchmaker, Вы писали:
W>Только то, что ты сам должен гарантировать, что ключи будут жить достаточно долго. То есть, что указатели из map должны ссылаться на валидные строки всё время жизни map.
сейчас эти строки генерятся макросом, который используется для описания интерфейсов, и который генерит дополнительную метаинфу.
но, т.к. это библиотечный код который используется несколькими коллегами — лучше таки на это не надеяться и копировать строку в мапу.
W>Так в C++ есть же прозрачные компараторы:
что-то я такое слышал, но не использовал... и, с++14 у нас пока не используется...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)