2010-10-20 74 views
5

有谁知道如果它传递一个boost :: unordered_set作为boost :: split的第一个参数是否为kosher?在libboost1.42-dev下,这似乎会导致问题。下面是导致该问题的一个小例子程序,把它test-split.cc:传递一个boost :: unordered_set作为结果映射到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; 
} 

然后,如果我运行下面的命令:

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

我收到了一堆抱怨像Valgrind的下面的一个(I有时也看不核心转储Valgrind的,但它似乎基于定时来改变):

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

这是一个Debian挤压盒;这里是我的相关信息:

$ 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 

但是,代码似乎如果我降级libboost1.42-dev的到libboost1.40-dev的做工精细。那么这是一个在1.42版本中的错误,还是我滥用boost :: split传入一个无法处理序列的容器?谢谢!

+0

FWIW,我只能用'boost :: unordered_set'重现这些valgrind错误,而GCC的'std :: unordered_set' valgrinds悄悄地。 – Cubbi 2010-10-20 19:35:55

+11

也许下面的例子可能值得考虑,因为它们更简单,更高效:http://www.codeproject.com/KB/recipes/Tokenizer.aspx特别是“一些简单的例子”部分。 – 2010-10-20 22:53:16

回答

2

这已在boost-users邮件列表中确认为boost :: unordered_set实现中的一个错误。邮件列表中有一个可用的修补程序,稍后会检查修补程序,希望能够及时提升1.45。

Boost-users: patch

Boost-users: confirmation

感谢大家寻找到这个!

0

显然,答案是

使用下面的代码,我得到编译时警告和unordered_set上的运行时断言(Visual C++ v10),而vector工作正常(除了最后一个元素中的空字符串,由于尾随'^' )。源(string)和目标容器之间

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

迭代器兼容性的问题。我会发布警告错误,但这是“战争与和平”模板警告之一。

编辑:

这看起来像在升压unordered_set的错误吗?当我使用以下内容时,它的工作方式与您的预期相同:

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

谢谢史蒂夫。你使用的是什么版本的提升? – 2010-10-20 19:39:51

+0

@Jeremy - 1.44.0 – 2010-10-20 19:50:54

+0

@Jeremy - 参见编辑 – 2010-10-20 20:59:51

0

我认为答案应该是。

读头(split.hppiter_find.hppsplit需要SequenceSequenceT& Result作为第一个参数,它传递给iter_split哪个范围-构建它从两个boost::transform_iterator S:

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

因此,所有需要这种类型的它有一个构造函数,它需要一对迭代器,这对迭代器的引用取决于std::string(或者,技术上来说,是BOOST_STRING_TYPENAME)。并有一个.swap()成员..并且有一个SequenceSequenceT::iterator类型,其类型为std::string

证明:

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

我认为应该unordered_set<std::string>满足这些要求也是如此。

+0

谢谢@Cubbi。所以你的结论是,这是Boost 1.42中的一个错误,并且在VisualC++/boost 1.44上@Steve发现的编译器警告是误导性的? – 2010-10-20 20:37:35

+0

@Jeremy Stribling:这正是我所期望的,看到我的测试和gcc的unordered_set如何工作,哪里不提升,但他们可能有一个很好的理由。我会在这里等待更多的答案并在调用它之前测试更多的错误。 – Cubbi 2010-10-20 21:01:31

+0

@Jeremy - 见编辑,我得到了'std :: unordered_set'而不是'boost :: unordered_set'的工作方式 – 2010-10-20 21:02:12

相关问题