2010-10-20 9 views
5

Est-ce que quelqu'un sait si c'est kasher de passer un boost :: unordered_set comme premier paramètre à boost :: split? Sous libboost1.42-dev, cela semble causer des problèmes. Voici un petit exemple de programme qui cause le problème, appelez test-split.cc:Passer un boost :: unordered_set comme résultat map to boost :: split

#include <boost/algorithm/string/classification.hpp> 
#include <boost/algorithm/string/split.hpp> 
#include <boost/unordered_set.hpp> 
#include <string> 

int main(int argc, char **argv) { 
    boost::unordered_set<std::string> tags_set; 
    boost::split(tags_set, "a^b^c^", 
       boost::is_any_of(std::string(1, '^'))); 
    return 0; 
} 

Ensuite, si je lance les commandes suivantes:

g++ -o test-split test-split.cc; valgrind ./test-split 

Je reçois un tas de plaintes comme valgrind celui qui suit (je aussi parfois voir coredumps sans valgrind, bien qu'il semble varier en fonction du temps):

==16843== Invalid read of size 8 
==16843== at 0x4ED07D3: std::string::end() const (in /usr/lib/libstdc++.so.6.0.13) 
==16843== by 0x401EE2: unsigned long boost::hash_value<char, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /tmp/test-split) 
... 
==16843== by 0x402248: boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >& boost::algorithm::split<boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >, char const [26], boost::algorithm::detail::is_any_ofF<char> >(boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >&, char const (&) [26], boost::algorithm::detail::is_any_ofF<char>, boost::algorithm::token_compress_mode_type) (in /tmp/test-split) 
==16843== by 0x40192A: main (in /tmp/test-split) 
==16843== Address 0x5936610 is 0 bytes inside a block of size 32 free'd 
==16843== at 0x4C23E0F: operator delete(void*) (vg_replace_malloc.c:387) 
==16843== by 0x4ED1EE8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/libstdc++.so.6.0.13) 
==16843== by 0x404A8B: void boost::unordered_detail::hash_unique_table<boost::unordered_detail::set<boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> > >::insert_range_impl<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, char const*>, boost::algorithm::split_iterator<char const*>, boost::use_default, boost::use_default> >(std::string const&, boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, char const*>, boost::algorithm::split_iterator<char const*>, boost::use_default, boost::use_default>, boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, char const*>, boost::algorithm::split_iterator<char const*>, boost::use_default, boost::use_default>) (in /tmp/test-split) 
... 
==16843== by 0x402248: boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >& boost::algorithm::split<boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >, char const [26], boost::algorithm::detail::is_any_ofF<char> >(boost::unordered_set<std::string, boost::hash<std::string>, std::equal_to<std::string>, std::allocator<std::string> >&, char const (&) [26], boost::algorithm::detail::is_any_ofF<char>, boost::algorithm::token_compress_mode_type) (in /tmp/test-split) 
==16843== by 0x40192A: main (in /tmp/test-split) 

Ceci est une boîte de Debian Squeeze; voici mon info système concerné:

$ g++ --version 
g++ (Debian 4.4.5-2) 4.4.5 
Copyright (C) 2010 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

$ dpkg -l | grep boost 
ii libboost-iostreams1.42.0   1.42.0-4      Boost.Iostreams Library 
ii libboost1.42-dev     1.42.0-4      Boost C++ Libraries development files 
$ uname -a 
Linux gcc44-buildvm 2.6.32-5-amd64 #1 SMP Fri Sep 17 21:50:19 UTC 2010 x86_64 GNU/Linux 

Cependant, le code semble fonctionner très bien si je downgrade libboost1.42-dev à libboost1.40-dev. Donc est-ce un bug dans le boost 1.42, ou est-ce que je fais un mauvais usage de boost :: split en passant dans un container qui ne peut pas gérer les séquences? Merci!

+0

FWIW, je ne peux reproduire que ces erreurs valgrind avec 'boost :: unordered_set', alors que' std :: unordered_set' de GCC est discret. – Cubbi

+11

Peut-être que les exemples suivants méritent d'être considérés, car ils sont plus simples et beaucoup plus efficaces: http: //www.codeproject.com/KB/recipes/Tokenizer.aspx Spécifiquement la section "Quelques exemples simples". –

Répondre

2

Cela a été confirmé sur la liste de diffusion boost-users comme un bug dans l'implémentation boost :: unordered_set.Il y a un correctif disponible sur la liste de diffusion, et un correctif sera bientôt disponible, espérons-le à temps pour boost 1.45.

Boost-users: patch

Boost-users: confirmation

Merci à tous pour la recherche dans ce!

0

Apparemment, la réponse est non oui.

En utilisant le code suivant, je reçois à la compilation des avertissements et une assert d'exécution (v10 Visual C++) sur le unordered_set tandis que le vector fonctionne très bien (à part une chaîne vide dans le dernier élément, en raison de la fuite «^»).

boost::unordered_set<std::string> tags_set; 
vector<string> SplitVec; // #2: Search for tokens 
boost::split(SplitVec, "a^b^c^", boost::is_any_of("^")); 
boost::split(tags_set, "a^b^c^", boost::is_any_of("^")); 

compatibilité itérateur entre la source (string) et le récipient cible est la question. Je signalerais l'erreur d'avertissement, mais c'est un de ces avertissements de modèle "Guerre et Paix".

EDIT:

Cela ressemble à un bug dans Boost unordered_set? Lorsque j'utilise ce qui suit, cela fonctionne comme prévu:

std::unordered_set<std::string> tags_set_std; 
boost::split(tags_set_std, string("a^b^c^"), boost::is_any_of(string("^"))); 
+0

Merci Steve. Quelle version de boost utilisez-vous? –

+0

@Jeremy - 1.44.0 –

+0

@Jeremy - voir EDIT –

0

Je pense que la réponse devrait être oui.

La lecture des en-têtes (split.hpp et iter_find.hpp) split prend un SequenceSequenceT& Result comme premier argument, qu'il passe à iter_split dont elle gamme construit à partir de deux boost::transform_iterator s:

SequenceSequenceT Tmp(itBegin, itEnd); 
Result.swap(Tmp); 
return Result; 

donc tout ce qu'il a besoin de ce type est qu'il a un constructeur qui prend une paire d'itérateurs qui déréférencent à std::string (ou, techniquement, à BOOST_STRING_TYPENAME). Et a un membre .swap() .. et a un type SequenceSequenceT::iterator dont le type est std::string.

preuve:

#include <boost/algorithm/string/classification.hpp> 
#include <boost/algorithm/string/split.hpp> 
#include <string> 
#include <iterator> 
#include <algorithm> 
#include <iostream> 
struct X 
{ 
    typedef std::iterator<std::forward_iterator_tag, 
      std::string, ptrdiff_t, std::string*, std::string&> 
      iterator; 
    X() {} 
    template<typename Iter> X(Iter i1, Iter i2) 
    { 
     std::cout << "Constructed X: "; 
     copy(i1, i2, std::ostream_iterator<std::string>(std::cout, " ")); 
     std::cout << "\n"; 
    } 
    void swap(X&) {} 
}; 
int main() 
{ 
    X x; 
    boost::split(x, "a^b^c^", boost::is_any_of(std::string(1, '^'))); 
} 

Je pense que unordered_set<std::string> devrait satisfaire à ces exigences aussi bien.

+0

Merci @Cubbi. Donc, votre conclusion est que c'est un bug quelque part dans Boost 1.42, et que les avertissements du compilateur vus par @Steve sur VisualC++/boost 1.44 sont trompeurs? –

+0

@Jeremy Stribling: C'est ce à quoi je m'attendais, vu comment mon test et unordered_set de gcc fonctionnent là où boost ne le fait pas, mais ils pourraient avoir une bonne raison. J'attendrais plus de réponses ici et testerais plus avant de l'appeler un bug. – Cubbi

+0

@Jeremy - voir edit, j'ai obtenu ceci en utilisant 'std :: unordered_set' au lieu de' boost :: unordered_set' –

Questions connexes