views:

3735

answers:

7

For new and completely revised tricks and dark corners of STL go here: Hidden Features and Dark Corners of STL

I've been using more "modern" c++ constructs for a while, but kind of superficially and not everywhere. I'm looking for open source projects to study that are good examples of Modern C++ and STL usage.

Things like what is suggested in Meyer's "Effective STL", such as trying to avoid for loops and replace them with more functional constructs, using boost::bind and boost::function, etc. These still feel a little unnatural to me, and when I have to get something done fast and working, I tend to drop back to libc and string.h (you can have my strtok when you pry it from my cold, dead, hands).

However, I've also had the positive experience of finding what would be a drastic change simplified because I've used these constructs, or being able to implement something with just a few lines of code because I had the right operators and functors lying around. In addition, I've recently been paying more attention to concurrency, and so this is becoming even more important to me.

Can you recommend some examples of well-written open source projects that make heavy use of the STL and other modern c++ techniques that I could study? I'm particularly interested in application code, browsing the boost sources has been helpful but it's by necessity very general because it's library code.

I'm interested in medium sized to larger projects, at least a few tens of thousands of lines. It's pretty easy to find examples that are a few hundred lines long but that's not too helpful.

Thank you.

+4  A: 

I'm not sure about "well written" but there are a few things out there like Hypertable and KFS that are system-level software that both use Boost and STL extensively.

I have heard some things about OpenOffice and Google Chrome but I haven't looked at their source code to know how precisely they use the STL. I've peeked at KDE but I wouldn't necessarily call that modern C++. I can tell you that some code I'm working on is doing lots of modern C++ but alas it's not open source -- although I think it's just a matter of time and patience to get the modern C++ approach out and have more open source projects adopting the idioms.

Dean Michael
Thanks, I'll look into those. That's been my feeling, too, that "modern" c++ gets used a lot on in-house projects but don't get a lot of more visible "public" usage.
i like KDE it's really modern C++ i think, using the pimpl idiom very strongly.
Johannes Schaub - litb
+14  A: 

Actually, I had a look into Google Chrome and would recommend it. Google's C++ coding guidelines are a good scaffold for large project. They are used/adopted in our team, too. Moreover, I am very happy that they are providing their C++ mocking and testing frameworks as open source projects. Very handy for large projects where you miss a lot of the nice test stuff from the Java/Managed world.

olli
I will check that out. I didn't realize Chrome was open-source! Thanks!
I looked through it, great code, great example but not very "Modern C++" style.
+16  A: 

Meyers is ok, however, if you really want to push yourself, you have to read

Andrei Alexandrescu - Modern C++ Design: Generic Programming and Design Patterns Applied

It will blow your mind. What you learn in the book describes the Loki library.

One of my favourites is the int to type conversions:

template <int v>
struct Int2Type
{
    enum { value = v };
};

I've used it in the past for my C++ XML serilisation library for pre-allocating vector<>'s before loading them with data:

// We want to call reserve on STL containers that provide that function,
// namely std::vector.
// However, we would get a compiler error if we tried to call reserve on
// a STL container that
// did not provide this function. This is the solution.
template <bool b, class T>
class CReserve
{
public:
    static void reserve(T &lst, const int &n)
    { reserve(lst, n, Loki::Int2Type<b>()); }

private:
    static void reserve(T &lst, const int &n, Loki::Int2Type<true>)
    { lst.reserve(n); }

    static void reserve(T &lst, const int &n, Loki::Int2Type<false>)
    { (void)lst; (void)n; }
};

Notice the private specialisations above. Well if you look closely, one calls reserve(), the other doesn't. This is a template specialisation using a bool as a type.

which in tern is used by:

template <bool bCallReserve, class T>
bool STLSerializeClassType(MSXML::IXMLDOMNodePtr pCurNode, T &lst, 
                           CXmlArchive &archive, const char *name)
{
    if(archive.IsStoring())
    {
     ...
    } else {
     lst.clear();

     T::size_type nCount(0);
     XML_ELEMENT(nCount);

     CReserve<bCallReserve, T>::reserve(lst, nCount);

     while(nCount--)
     {
      T::value_type temp;
      temp.SerializeXml(archive, pCurNode);
      lst.push_back(temp);
     }
    }
}

To make things simple in users C++ code, I added a lot of helper definitions

#define SERIALIZE_XML_STL_CLASS(list_name, bCallReserve) \
(HS::STLSerializeClassType<(bCallReserve)>
    (pCurNode, (list_name), archive, (#list_name))
)

so in your code you'd use something like:

std::list<CFred> fredList;
SERIALIZE_XML_STL_CLASS(fredList, false);

or for vectors:

vector<CFred> fredList;
SERIALIZE_XML_STL_CLASS(fredList, true);

Anyway, I'll stop wittering on... Thats just putting the simple Int2Type<> template to good use. There's loads of clever stuff like getting the compiler to compute a ton of stuff beforehand by clever use of enums. Truly awsome book.

Simon Hughes
+1 for blowing my mind
rmeador
Why not write a template reserve function that does nothing, and then a specialization for std::vector that calls reserve on it? That way the caller doesn't have to pass a bool to control whether reserve should be called. It just figures it out based on the container type.
Daniel Earwicker
Yeah, I love that book. That's exactly the type of stuff that I'm trying to apply on a larger scale.
I got mind overflow. Does this code stop looking like "write only" after reading the above mentioned book?
Muxecoid
infact, you can do better than that with traits by not explicitly specifying TRUE/FALSE in SERIALIZE_XML_STL_CLASS(...), imho.
Comptrol
All that to avoid an if() on a bool at runtime?
+3  A: 

Not really projects, but here are a couple of snippets:

Sample use of boost::thread / boost::bind:

class X { void expensive_operation( int argument ); };

int main()
{
   X x;
   boost::thread thr( boost::bind( &X::expensive_operation, &x, 1000 ) );
   std::cout << "Thread is processing..." << std::endl;
   thr.join();
}

std::copy, std::transform, BOOST_FOREACH:

int main()
{
   std::vector<std::string> v;
   std::copy( std::istream_iterator<std::string>( std::cin ), 
              std::istream_iterator<std::string>(), std::back_inserter(v) );
   BOOST_FOREACH( std::string & s, v )
   {
      transform(s.begin(), s.end(), s.begin(), toupper);
   }
   std::copy( v.begin(), v.end(), 
              std::ostream_iterator<std::string>(std::cout, " ") );
}

The snippet will read from user input a set of strings into a vector. Then for each string in the vector it will convert to upper case and finally output the result.

Our applications make heavy use of boost::signals and boost::function to decouple classes where it is not time critical, mainly in UI classes:

class ContactDetailPanel;
class ContactListPanel {
public:
   void update();
   void edit_completed( bool change );
   boost::function< void ( Contact & ) >& edit_contact();    
};
int main()
{
   ContactListPanel clp;
   ContactDetailPanel cdp;

   clp.edit_contact() = boost::bind( &ContactDetailPanel::edit, &cdp, _1 );
   cdp.edit_completed() = boost::bind( &ContactListPanel::edit_completed, &clp, _1 );
   ui::signal_update().connect( boost::bind( &ContactListPanel::update, &clp ) );     
}

Each panel has no information about other panels. The code that binds panels together has the flow knowledge (to edit a contact use contact detail panel, notify edit completion to contact list panel). Also, there is a global signal to notify panels of updates to the underlying model.

This is specially helpful when you need to write test code. There is no need to implement mock classes to replace working code for testing. Tests just instantiate the class and connect the functions/signals to test code without the tested class noticing, following the principle of least intrusion during tests.

David Rodríguez - dribeas
`boost::to_upper(s)` could replace `transform(s.begin(), s.end(), s.begin(), toupper)`.
J.F. Sebastian
`for_each(v.begin(), v.end(), cout << _1 << " ");` or `foreach (string s, v) cout << s << " ";` could replace `std::copy( v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, " ") );`
J.F. Sebastian
cout << _1 << " " - requires boost::lambda, which I have tried but do not feel comfortable enough to write a snippet out of the top of my head. I did not know about boost::to_upper(s), thanks.
David Rodríguez - dribeas
+3  A: 

Adobe has published a good deal of modern C++ open-source code in the last couple of years, which is probably worth checking out:

http://opensource.adobe.com/wiki/display/site/Home

I believe their GIL library either has been, or is in the process of being added to Boost. their STLab contains a ton of functionality too which, from what I've seen is very clean, and very much STL-style.

jalf
I tried to use GIL about a year ago and found it really amazing from a design standpoint, but unrealistic for real world work. Compile times were bad, it was amazingly difficult to debug, and having to any_image<> type was awkward. I'm keeping my eye on it for the future tho.
+7  A: 

Here, you find several interesting examples of how Boost is being used in open source projects:
http://www.boost.org/users/uses_open.html

Pukku
That's great! I always miss the obvious places to look..
I'd rather have found one excellent example, these each use boost and Modern c++ to varying and lesser degrees, but this was the best source of real-world examples (not just snippets) that I could find.
A: 

Here is a snippet to concatenate vector of strings into one string:

vector<string> vecstr;
vecstr.push_back("abc");
vecstr.push_back("efg"); // etc.
string concat = accumulate( vecstr.begin(), vecstr.end(), string("") );