stl::set

Posted by Benjamin Close on November 13, 2008 under Programming | 3 Comments to Read

Working with Mark’s dnl code, we came across an interesting issue. Mark had used the stl::set class for some of his code and whilst it compiled fine under Visual Studio, it failed to compile under gcc/g++. With the error:

dnlCommon/Logger.cpp: In member function 'void dnlCommon::Logger::setMask(std::ostream&, std::bitset<5ul>)':
dnlCommon/Logger.cpp:64: error: invalid initialization of reference of type 'dnlCommon::Logger::LoggerPair&' from expression of type 'const dnlCommon::Logger::LoggerPair'
/usr/local/lib/gcc-4.0.4/include/c++/bits/stl_algo.h: In function '_OutputIterator std::remove_copy(_InputIterator, _InputIterator, _OutputIterator, const _Tp&) [with _InputIterator = std::_Rb_tree_const_iterator<dnlCommon::Logger::LoggerPair>, _OutputIterator = std::_Rb_tree_const_iterator<dnlCommon::Logger::LoggerPair>, _Tp = dnlCommon::Logger::LoggerPair]':
/usr/local/lib/gcc-4.0.4/include/c++/bits/stl_algo.h:1112:   instantiated from '_ForwardIterator std::remove(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = std::_Rb_tree_const_iterator<dnlCommon::Logger::LoggerPair>, _Tp = dnlCommon::Logger::LoggerPair]'
dnlCommon/Logger.cpp:54:   instantiated from here
/usr/local/lib/gcc-4.0.4/include/c++/bits/stl_algo.h:1037: error: passing 'const dnlCommon::Logger::LoggerPair' as 'this' argument of 'dnlCommon::Logger::LoggerPair& dnlCommon::Logger::LoggerPair::operator=(const dnlCommon::Logger::LoggerPair&)' discards qualifiers

It turned out that the issue occurred with the assignment operator (operator = ) on the stl::set class. Tracing the problem we found that set<TYPE>::iterator is const rather than non cost. Hence calling stl functions that made use of the iterators but also the assignment operator would fail.

Looking further into the problem I found:

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // DR 103. set::iterator is required to be modifiable,
      // but this allows modification of keys.
      typedef typename _Rep_type::const_iterator iterator;
      typedef typename _Rep_type::const_iterator const_iterator;

Hmm, that’s strange. A bit of googling revieled the problem to be an issue with the stl standard. Fixes to gcc/g++ are listed at http://gcc.gnu.org/onlinedocs/libstdc++/ext/howto.html in particular error 103 is listed at http://gcc.gnu.org/onlinedocs/libstdc++/ext/lwg-defects.html#103
So it looks like the bug was ratified by the C++ committee in 1998 and it still isn’t fixed in Visual Studio 2005 (VC++ 8.0) !

Stl::reverse iterator

Posted by Benjamin Close on under Programming | Be the First to Comment

I was coding a little program a while back when I found a Quirk about the stl reverse_iterator. Use of the iterator is quite easy until you have to delete from one. I tried the normal way of:

vector<sometype>::reverse_iterator myiterator...
..
..
myvector.erase(myiterator).

only to find the code didn’t compile. A little baffled I started to looking into why. It turns out you Can’t’ delete from a reverse iterator directly. So the question is How do you delete from a reverse iterator?.

Not wanting to do a full forward traversal to get to the same point I did some Googling. Eventually I found the page: http://www.ddj.com/dept/cpp/184401406

which explains why you can’t delete from the reverse iterator. More importantly it indicates a way that you can delete from the reverse_iterator. So how?

 void Manager::raiseWindow(WMWindow* wmwindow)
 {
   vector<WMWindow*>::reverse_iterator it = windows.rbegin();
   while(it != windows.rend())
   {
     if (*it == wmwindow)
     {
      // why ++it see http://www.ddj.com/dept/cpp/184401406
      windows.erase((++it).base());
      windows.push_back(wmwindow);
      break;
     }
     it++;
   }

   wmwindow->raise();
 }

</code>

Gives an example of how to do it. However, be aware, doing the above erase, invalidates the iterator so don’t go trying to use it again afterwards! }

Was this helpful?


Throw some money in the tip jar