Jac*_*icz 14 c++ boost visual-c++ boost-foreach
我知道boost或编译器应该是最后的责任,但我在这里看不到另一种解释.我正在使用msvc 2008 SP1并提升1.43.
在下面的代码片段中,执行永远不会离开第三个 BOOST_FOREACH循环
typedef Graph<unsigned, unsigned>::VertexIterator Iter;
Graph<unsigned, unsigned> g;
g.createVertex(0x66);
// works fine
Iter it = g.getVertices().first, end = g.getVertices().second;
for(; it != end; ++it)
;
// fine
std::pair<Iter, Iter> p = g.getVertices();
BOOST_FOREACH(unsigned handle, p)
;
// fine
unsigned vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// oops, infinite loop
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// ... last block repeated 6 times
Run Code Online (Sandbox Code Playgroud)
迭代器代码:
class Iterator
: public boost::iterator_facade<Iterator, unsigned const,
boost::bidirectional_traversal_tag>
{
public:
Iterator()
: list(NULL), handle(INVALID_ELEMENT_HANDLE)
{}
explicit Iterator(const VectorElementsList &list, unsigned handle = INVALID_ELEMENT_HANDLE)
: list(&list), handle(handle)
{}
friend std::ostream&
operator<<(std::ostream &s, const Iterator &it)
{
s << "[list: " << it.list <<", handle: " << it.handle << "]";
return s;
}
private:
friend class boost::iterator_core_access;
void increment()
{
handle = list->getNext(handle);
}
void decrement()
{
handle = list->getPrev(handle);
}
unsigned const& dereference() const
{
return handle;
}
bool equal(Iterator const& other) const
{
return handle == other.handle && list == other.list;
}
const VectorElementsList<T> *list;
unsigned handle;
};
Run Code Online (Sandbox Code Playgroud)
一些ASM乐趣:
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
// initialization
013E1369 mov edi,dword ptr [___defaultmatherr+8 (13E5034h)] // end iterator handle: 0xFFFFFFFF
013E136F mov ebp,dword ptr [esp+0ACh] // begin iterator handle: 0x0
013E1376 lea esi,[esp+0A8h] // begin iterator list pointer
013E137D mov ebx,esi
013E137F nop
// forever loop begin
013E1380 cmp ebp,edi
013E1382 jne main+238h (13E1388h)
013E1384 cmp ebx,esi
013E1386 je main+244h (13E1394h)
013E1388 lea eax,[esp+18h]
013E138C push eax
// here iterator is incremented in ram
013E138D call boost::iterator_facade<detail::VectorElementsList<Graph<unsigned int,unsigned int>::VertexWrapper>::Iterator,unsigned int const ,boost::bidirectional_traversal_tag,unsigned int const &,int>::operator++ (13E18E0h)
013E1392 jmp main+230h (13E1380h)
vertex_count++;
// forever loop end
Run Code Online (Sandbox Code Playgroud)
很容易看到迭代器句柄缓存在EBP中,尽管调用了迭代器operator ++()函数,但它永远不会增加.
我用一个派生自std :: iterator的替换了Itarator implmentation并且问题仍然存在,所以这不是iterator_facade错误.此问题仅存在于msvc 2008 SP1 x86和amd64发布版本上.调试构建在msvc 2008和msvc 2010上的调试/发布版本上,gcc 4.4(linux)工作正常.此外,BOOST_FOREACH块必须重复执行10次.如果它被重复9次,那就没关系了.
我想由于BOOST_FOREACH使用模板技巧(const auto_any),编译器假定迭代器句柄是常量并且永远不会再次读取其实际值.
我会很高兴听到我的代码是错误的,纠正它并继续使用BOOST_FOREACH,我发现它(与BOOST_FOREVER :)相反.
可能与以下内容有关:为什么BOOST_FOREACH有时不能与C++字符串一起工作?
编辑:
我准备了简化的项目来重现这个问题.没有模板,没有默认参数,没有任何东西.到这里:http://yabcok.nazwa.pl/ugly3.zip
Looks to me like this bug in VC++ regarding default values in template functions.
There's a very similar bug here in August 2009 (closed as 'fixed' by M$ in their next release)... it's consistent in tons of ways: it's VC++ specific and works in GCC, results in intermittent failure with default template arguments (but never compile-time issues), and the problem only crops up on the second instantiation.
That said, I can't explain the compiler output, or the magic 10 loops... :-)
VC++ even has an old article on workarounds with templates. with very similar bugs so recently, and how consistent your bug and Color_of_Green's bug seem, it's probably VC++ and not Boost.
我猜?这些签名令人窒息:const T & data = T()在 graph_elements_collection.h 中。MSFT 建议将其更改为const T data = T(). 要验证它是否与此编译器错误相关,请尝试一下,或者 MSFT 发布的解决方法...此处...
| 归档时间: |
|
| 查看次数: |
1211 次 |
| 最近记录: |