2010-10-20 10 views
5

Czy ktoś wie, czy to koszerne przekazanie boost :: unordered_set jako pierwszego parametru do zwiększenia :: split? Pod libboost1.42-dev to wydaje się powodować problemy. Oto mały przykład program, który powoduje problem, nazwać test-split.cc:Przekazywanie boost :: unordered_set jako mapa wyników do 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; 
} 

Następnie, jeśli mogę uruchomić następujące polecenia:

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

mam kilka skarg w valgrind jak ten, który następująco (ja też czasem zobaczyć coredumps bez valgrind, choć wydaje się różnić w zależności od czasu):

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

to pole Debian Squeeze; oto moja istotne informacje o systemie:

$ 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 

Jednak kod wydaje się działać prawidłowo, jeśli downgrade libboost1.42-dev do libboost1.40-dev. Czy jest to błąd w podbiciu 1.42, czy też nadużywam boost :: split przez przekazanie w kontenerze, który nie może obsłużyć sekwencji? Dzięki!

+0

FWIW, jestem w stanie odtworzyć te błędy valgrind za pomocą 'boost :: unordered_set', a GCC' std :: unordered_set' cicho. – Cubbi

+11

Być może poniższe przykłady mogą być warte rozważenia, ponieważ są prostsze i znacznie bardziej wydajne: http: //www.codeproject.com/KB/recipes/Tokenizer.aspx W szczególności sekcja "Kilka prostych przykładów". –

Odpowiedz

2

Zostało to potwierdzone na liście mailingowej użytkowników boost jako błąd w implementacji boost :: unordered_set.Dostępna jest łata na liście mailingowej, a poprawka zostanie wkrótce sprawdzona, mam nadzieję, że na czas o doładowaniu 1.45.

Boost-users: patch

Boost-users: confirmation

Dzięki wszystkim za patrząc na to!

0

Najwyraźniej odpowiedź brzmi: nr tak.

Korzystanie poniższy kod, pojawia się w czasie kompilacji ostrzeżenia i dochodzić do uruchamiania aplikacji (Visual C++ v10) na unordered_set natomiast vector działa dobrze (oprócz pustego ciągu w ostatnim elemencie, ze względu na „^” spływu).

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 kompatybilność pomiędzy źródłem (string) i pojemnika docelowego jest problem. Wysłałbym komunikat ostrzegawczy, ale jest to jeden z ostrzeżeń o szablonie "Wojny i pokoju".

EDIT:

To wygląda na błąd w Boost, unordered_set? Gdy korzystam z poniższego, działa on tak, jak się spodziewasz:

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

Dzięki Steve. Z jakiej wersji wzmocnienia korzystasz? –

+0

@Jeremy - 1.44.0 –

+0

@Jeremy - patrz edycja –

0

Myślę, że odpowiedź powinna brzmieć "tak".

Odczyt nagłówki (split.hpp i iter_find.hpp) split wybija SequenceSequenceT& Result jak pierwszy argument, który przechodzi do iter_split których zakres, konstruuje się z dwóch boost::transform_iterator s:

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

Więc potrzebuje tego rodzaju jest to, że ma konstruktor, który pobiera parę iteratorów, które mają dereferencję do std::string (lub technicznie do BOOST_STRING_TYPENAME). Ma członka .swap() .. i ma typ, którego typ to std::string.

dowód:

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

myślę że unordered_set<std::string> powinny spełniać te wymagania, jak również.

+0

Dzięki @Cubbi. Więc twoim wnioskiem jest to, że jest to błąd gdzieś w Boost 1.42, i że ostrzeżenia kompilatora widziane przez @Steve w VisualC++/boost 1.44 wprowadzają w błąd? –

+0

@Jeremy Stribling: To jest to, czego się spodziewałbym, widząc, jak mój test i unordered_set gcc działają tam, gdzie boost nie działa, ale mogli mieć dobry powód. Czekałbym na więcej odpowiedzi tutaj i przetestuję więcej zanim nazwałbym go błędem. – Cubbi

+0

@Jeremy - patrz edit, działa to z 'std :: unordered_set' zamiast' boost :: unordered_set' –

Powiązane problemy