2010-10-20 6 views
5

Weiß jemand, ob es koscher ist, boost :: unordered_set als ersten Parameter an boost :: split zu übergeben? Unter libboost1.42-dev scheint dies Probleme zu verursachen. Hier ist ein kleines Beispiel-Programm, das das Problem verursacht, nennt es test-split.cc:Ein boost :: unordered_set als Ergebniskarte an boost :: split übergeben

#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; 
} 

Dann, wenn ich die folgenden Befehle ausführen:

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

ich eine Reihe von Beschwerden in valgrind bekommen denjenigen, der folgt (ich manchmal auch coredumps ohne valgrind sehen, obwohl es basierend auf Timing zu variieren scheint):

==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) 

Dies ist eine Debian Squeeze-Box; hier ist mein relevantes Systeminfo:

$ 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 

Allerdings scheint der Code gut zu funktionieren, wenn ich libboost1.42-dev libboost1.40-dev degradieren. Also, ist das ein Bug in Boost 1.42 oder missbrauche ich boost :: split, indem ich einen Container übergebe, der keine Sequenzen verarbeiten kann? Vielen Dank!

+0

FWIW, ich kann diese Valgrind-Fehler nur mit 'boost :: unordered_set' reproduzieren, während GCCs' std :: unordered_set' ruhig weiterläuft. – Cubbi

+11

Vielleicht sind die folgenden Beispiele vielleicht eine Überlegung wert, da sie einfacher und weitaus effizienter sind: http://www.codeproject.com/KB/recipes/Tokenizer.aspx Insbesondere der Abschnitt "Einige einfache Beispiele". –

Antwort

2

Dies wurde in der boost-users-Mailingliste als Fehler in der boost :: unordered_set-Implementierung bestätigt.Es gibt einen Patch auf der Mailing-Liste, und ein Fix wird bald eingecheckt, hoffentlich rechtzeitig für Boost 1.45.

Boost-users: patch

Boost-users: confirmation

Vielen Dank allen für in diese suchen!

0

Offenbar ist die Antwort nein ja.

Mit dem folgenden Code bekomme ich Kompilierungswarnungen und eine Laufzeit-Assert (Visual C++ v10) auf der unordered_set, während die vector gut funktioniert (abgesehen von einer leeren Zeichenfolge im letzten Element, aufgrund der abschließenden '^').

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("^")); 

Iterator Kompatibilität zwischen Quelle (string) und der Zielbehälter ist das Problem. Ich würde den Warnfehler posten, aber es ist eine dieser "War and Peace" Vorlagenwarnungen.

EDIT:

Das sieht wie ein Fehler in Boost-unordered_set? Wenn ich Folgendes benutze, funktioniert es so, wie Sie es erwarten würden:

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

Danke Steve. Welche Boost-Version verwendest du? –

+0

@ Jeremy - 1.44.0 –

+0

@ Jeremy - siehe EDIT –

0

Ich denke, die Antwort sollte ja sein.

Lesen der Header (split.hpp und iter_find.hpp) split nimmt SequenceSequenceT& Result als erstes Argument, das es zu iter_split gibt, die sie von zwei boost::transform_iterator s Entfernungs-Konstrukte:

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

Also alles was man braucht dieses Typs ist, dass es einen Konstruktor hat, der ein Paar von Iteratoren nimmt, die auf std::string (oder technisch zu BOOST_STRING_TYPENAME) dereferenzieren. Und hat ein .swap() Mitglied .. und hat einen SequenceSequenceT::iterator Typ, dessen Typ ist std::string.

Beweis:

#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, '^'))); 
} 

Ich denke, dass unordered_set<std::string> auch diese Anforderungen erfüllen sollte.

+0

Danke @ Cubbi. Ihre Schlussfolgerung ist, dass dies irgendwo in Boost 1.42 ein Bug ist und dass die Compiler-Warnungen, die von @Steve auf VisualC++/boost 1.44 gesehen werden, irreführend sind? –

+0

@ Jeremy Stribling: Es ist, was ich erwarten würde, zu sehen, wie mein Test und gcc's ungeordnetes_set funktionieren, wo boost's nicht funktioniert, aber sie könnten einen guten Grund gehabt haben. Ich würde hier auf weitere Antworten warten und mehr testen, bevor ich es als Bug bezeichnen würde. – Cubbi

+0

@ Jeremy - siehe bearbeiten, ich habe dies mit 'std :: unordered_set' anstelle von' boost :: unordered_set' arbeiten –

Verwandte Themen