What Are SCARY Iterators?

Diego DagumHi there! I’m Diego Dagum, a Program Manager with the Visual C++ team.

As Stephan announced last September when Visual Studio 11 Developer Preview was released, our STL implementation comes with SCARY iterators. On Stephan’s words,

”(…) as permitted but not required by the C++11 Standard, SCARY iterators have been implemented, as described by N2911 “Minimizing Dependencies within Generic Classes for Faster and Smaller Programs and N2980 “SCARY Iterator Assignment and Initialization, Revision 1.

What are they useful for? What are they, in the first place? What’s so SCARY about them?

In this post I’ll demystify any mystery about SCARY iterators, hopefully inspiring in you some design best practice for your own template classes.

 

 

 

Imagine the following situation:

  1. // the list below uses an allocator other than the default
  2. list<int, stdext::allocators::allocator_unbounded<int>> l;
  3.  
  4. // Is the following line valid? (i.e. does it compile?)
  5. list<int>::iterator iter(l.begin());

 

Does it compile or not? Well, I tried to compile that code using a pre-v11 Visual C++ compiler, getting the following error:

  1. error C2664: ‘std::_List_iterator<_Mylist>::_List_iterator(const std::_List_iterator<_Mylist> &)’ : cannot convert parameter 1 from ‘std::_List_iterator<_Mylist>’ to ‘const std::_List_iterator<_Mylist> &’
  2. 1>          with
  3. 1>          [
  4. 1>              _Mylist=std::_List_val<int,std::allocator<int>>
  5. 1>          ]
  6. 1>          and
  7. 1>          [
  8. 1>              _Mylist=std::_List_val<int,stdext::allocators::allocator_unbounded<int>>
  9. 1>          ]
  10. 1>          and
  11. 1>          [
  12. 1>              _Mylist=std::_List_val<int,std::allocator<int>>
  13. 1>          ]
  14. 1>          Reason: cannot convert from ‘std::_List_iterator<_Mylist>’ to ‘const std::_List_iterator<_Mylist>’
  15. 1>          with
  16. 1>          [
  17. 1>              _Mylist=std::_List_val<int,stdext::allocators::allocator_unbounded<int>>
  18. 1>          ]
  19. 1>          and
  20. 1>          [
  21. 1>              _Mylist=std::_List_val<int,std::allocator<int>>
  22. 1>          ]
  23. 1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

 

The reason I’ve got this error is that in the last line of the code I’m trying to initialize iter (an iterator over a list of int using the default list allocator std::allocator<int>) with an iterator which looks similar excepts that it corresponds to a list allocated by the alternative stdext::allocators::allocator_unbounded<int>. Sad but true, these are different specializations of list of ints; therefore, conversions between them can’t be handled by default.

From a compiler perspective there is nothing wrong here. From a practical standpoint, however, there isn’t any semantic dependence between list iterators and list allocators. And, in general for all STL containers, iterators only depend (semantically speaking) on the container element type.

Based on research paper N2911Minimizing Dependencies within Generic Classes for Faster and Smaller Programs“, the acronym SCARY describes

Assignments and initializations that are Seemingly erroneous (appearing Constrained by conflicting generic parameters), but Actually work with the Right implementation (unconstrained bY the conflict due to minimized dependencies)

… or just SCARY, you know… (Don’t kill the messenger, I wasn’t the inventor of this name!)

 

In our STL11 implementation, iterator dependencies were minimized so the precedent code compiles fine. The same applies for any other STL container iterator (vector, deque, etc.) This said, you’ll be able to implement novel algorithms in ways that were previously impossible due to type mismatches. Not that scary, after all!

 

 

 

Epilogue

The issue that prevented my program to compile isn’t just tied to a particular STL implementation. In fact, as N2911 “Minimizing Dependencies within Generic Classes for Faster and Smaller Programs tells, it’s a more general issue that can happen when designing generic classes. In its authors’ own words:

We advocate a design principle whereby the dependencies between the members and the type parameters of a generic class should be minimized, we propose techniques to realize this principle, and we show that the principle can be leveraged to achieve faster and smaller programs.

Worth reading. Enjoy!

 

PS. A HUGE THANKS to Stephan T. Lavavej (Mr. STL) for reviewing this post.