19 ms·
It would be both counterproductive and a premature optimization to learn C++ by first learning the STL containers. The only container that the C++ newcomer nee
by palish 19y ago
It would be both counterproductive and a premature optimization to learn C++ by first learning the STL containers. The only container that the C++ newcomer needs to learn is the dynamically allocated array. The statement "vector and map are pretty simple" just isn't true. STL and Boost have a lot of subtleties:
1) It is important to write STL code in the correct style. STL containers should be typedef'd before they are used and an iterator shouldn't be used directly to access an item (otherwise debugging becomes more difficult and your code becomes harder to read). For example,
typedef std::list< Puppy > PuppyContainer;
PuppyContainer puppies;
for( PuppyContainer::iterator it = puppies.begin(); it != puppies.end(); ++it )
{
Puppy* puppy = *it;
// do something with your puppy
}
... rather than ...
std::list< Puppy > PuppyContainer;
for( std::list< Puppy >::iterator it = puppies.begin(); it != puppies.end(); ++it )
{
// do something with *it
}
2) STL frequently allocates memory. Those allocations are also hidden from you, so it is easy to misunderstand the true cost of frequently using STL containers. Even a simple operation like acquiring an iterator can cause an allocation.
I work at a game company. In their game's code base, the pervasiveness of STL has been attributed to millions of micro-allocations every frame of their game. (A micro-allocation is an allocation of under 128 bytes.) The result is hopelessly fragmented memory, which means that:
- A relatively small 10MB allocation can cause a crash even when there is clearly more than 10MB free memory.
- A lot of code runs slowly because almost none of the code can take advantage of the CPU cache.
3) Using STL can add code complexity and make your code harder to read. Which of these is easier for a newcomer to understand?
for( size_t i = 0; i < _numPuppies; ++i )
if( _puppies[ i ].ID() == finding )
{
/* do something with that puppy */
break;
}
... or ...
PuppyContainer::iterator it = _puppies.find( finding );
if( it != _puppies.end() )
{
Puppy* puppy = it->second;
/* do something with that puppy */
}
The second example isn't intuitively easy to write unless you're already familiar with std::map.
Check out my Radix Sort example. I could have used a couple std::vectors, but the result is equivalent and simple: http://dl.getdropbox.com/u/315/programming/exaples/radix_sort_example.cpp http://dl.getdropbox.com/u/315/programming/exaples/radix_sor...
4) It takes a lot of time to learn every facet of the C++ language. And the more you learn, the more other people can't read what you write because of your advanced knowledge. (Try understanding boost/bind.hpp.)
5) Most importantly, most design problems are architectural and not structural. As long as your code works and is reasonably clean and well-commented, it is good and safe code. It is more important to master a subset of C++ than to have a working knowledge of the entire language.
- dataangel 19y agoWhat STL implementation are you using that's making so many tiny allocations? Could you give some more detail about what operations trigger the allocating? Admittedly, I haven't tried writing a game engine in C++ yet, but I do write a lot of plot rendering code, and I try to keep my rendering loops "read only," so if STL containers are used, only const member functions are called. Retrieving a member from a vector for example, shouldn't involve any allocations on the heap. Unless you're counting stack too. I could see STL implementations combined with a compiler poor at inlining resulting in a lot of extra call depth. Edit: Also, if the original poster is mostly using C++ due to the platform (I don't know what Symbian supports) it's unlikely he has the same sort of performance requirements you do. Most applications don't need to worry about 128-byte allocations.
- palish 19y agoOur compiler is Visual Studio 2005. John Ratcliff would know the details... He's spent about a month implementing detailed memory tracking and statistics. A big culprit is our pervasive use of std::string, but every other container also contributes.
- yummyfajitas 19y agoGotta disagree with you on some of this. On point 1, I see nothing wrong with this: list<Puppy> cutelittlepuppies; ... BOOST_FOREACH(Puppy p, cutelittlepuppies){ p.pet(); } Use typedefs for more complex templates. My rule of thumb: if it's faster to read and understand the template than to find the typedef, don't use a typedef. As for the allocations (point 2), not usually a big deal outside of games. The added safety is worth the performance hit.
- palish 19y agoBoost is nice, but it would require too much time for the original poster to set it up and to learn how to use it. He's almost completely new to C++ and would like to be productive within a month. Realistically, there about 22 work days per month. Since setting up Boost for the first time is an all-day affair, that alone is almost 5% of his time. Would that time investment really provide more than a 5% return? Not only that, but using Boost results in non-portable code. Boost could be the reason that your game cannot be ported to the PS3 or to the XBox 360 platforms. (Both STL and Boost can also consume a lot of precious memory on those platforms.) Also, there is still a huge market outside of games where it isn't necessarily a good idea to use STL and Boost. Embedded systems, flight simulators, so on. How do you know that STL and Boost compile to equivalent code when your compiler isn't GCC or Visual Studio? So Boost limits your options and it is debatable whether its productivity return is greater than its cost. In that light, why is it a good idea to train yourself to depend on it? If you take a job at a company where Boost is not an option, you will: - be forced to not use any code in your personal library that references Boost. - be forced to expand all of the BOOST_FOREACH() statements into for( std::list< Puppy >::iterator ... ). (Also, you left off the std:: on "std::list". I'd like to mention that "using namespace std" is a bad idea.) Because of that, typedef'ing each STL container before using it is a good idea. As for finding the definition of the typedef, the definition should almost always be within the same class that uses it. If you install Visual Assist you can use the "Go To Definition" feature (Alt-G) to warp directly to the typedef's definition. If you're forced to use C++, I assert that you can be more productive, portable, efficient, and reliable by avoiding Boost and most of STL.