C ++ unordered_map ricerca senza build stringhe

Ho codice C ++ che indaga su una stringa BIG e corrisponde a molte sottostringhe. Per quanto ansible, evito di build std :: stringhe, codificando sottostringhe come questa:

char* buffer, size_t bufferSize 

Ad un certo punto, tuttavia, mi piacerebbe cercare una sottostringa in uno di questi:

 std::unordered_map stringToInfo = {... 

Quindi, per farlo, vado:

 stringToInfo.find(std::string(buffer, bufferSize)) 

Questo costruisce una stringa std :: per il solo scopo della ricerca.

Ho l’impressione che ci sia un’ottimizzazione che potrei fare qui, cambiando il tipo-chiave di unordered_map con una sorta di temporaneo impostore di stringhe, una class come questa …

 class SubString { char* buffer; size_t bufferSize; // ... }; 

… fa la stessa logica di std :: string in hash e compare, ma poi non rilascia il suo buffer quando viene distrutto.

Quindi, la mia domanda è: c’è un modo per ottenere le classi standard per farlo, o scrivo questa class da solo?

Quello che vuoi fare è chiamato ricerca eterogenea . Dal momento che C ++ 14 è stato supportato per std::map::find e std::set::find (note versioni (3) e (4) delle funzioni, che sono basate sul tipo di valore di ricerca). È più complicato per i contenitori non ordinati perché devono essere indicati o trovare funzioni hash per tutti i tipi di chiavi che produrranno lo stesso valore di hash per lo stesso testo. C’è una proposta in esame per un futuro standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r0.html

Nel frattempo, è ansible utilizzare un’altra libreria che supporta già la ricerca eterogenea, ad esempio boost::unordered_map::find .

Se vuoi attenersi a std::unordered_map , puoi evitare di creare così tanti oggetti temporanei per le stringhe memorizzando un membro std::string insieme a unordered_map che puoi riassegnare i valori, quindi passare quella string per find . Si può incapsulare questo in una class contenitore personalizzata.

Un altro percorso è scrivere una class personalizzata da utilizzare come chiave contenitore non ordinato:

 struct CharPtrOrString { const char* p_; std::string s_; explicit CharPtrOrString(const char* p) : p_{p} { } CharPtrOrString(std::string s) : p_{nullptr}, s_{std::move(s)} { } bool operator==(const CharPtrOrString& x) const { return p_ ? x.p_ ? std::strcmp(p_, x.p_) == 0 : p_ == x.s_ : x.p_ ? s_ == x.p_ : s_ == x.s_; } struct Hash { size_t operator()(const CharPtrOrString& x) const { std::string_view sv{x.p_ ? x.p_ : x.s_.c_str()}; return std::hash()(sv); } }; }; 

È quindi ansible CharPtrOrString da std::string s per l’utilizzo nelle chiavi del contenitore non ordinato, ma costruirne uno a basso costo dal proprio const char* ogni volta che si chiama find . Nota che l’ operator== sopra deve capire quale hai fatto (la convenzione usata è quella se il puntatore è nullptr allora il membro std::string in uso) in modo tale che confronta i membri in uso. La funzione hash deve assicurarsi che una std::string con un particolare valore testuale produrrà lo stesso hash di un const char* (che non è predefinito per GCC 7.3 e / o Clang 6 – Io lavoro con entrambi e ricordo uno ha avuto un problema ma non quale).