Welcome to another installment of C9 Lectures covering the powerful general C++ library, STL. Joining us once again is the great Stephan T. Lavavej, Microsoft's keeper of the STL cloth (this means he manages the partnership between the owners of STL (dinkumware) and Microsoft, including, of course, bug fixes and enhancements to the STL that ships as part of Visual C++). Simply, Stephan is a C++ library developer.

As is Stephan's nature, he elaborates on technical details in very substantive way. The Standard Template Library, or STL, is a C++ library of container classes, algorithms, and iterators. STL provides many fundamental algorithms and data structures. Furthermore, the STL is a general-purpose library: its components are heavily parameterized, such that almost every component in the STL is a template.

In part 3, Stephan focuses on shared_ptrand unique_ptr. You will also learn a bit about exception safety and, of course, get another challenging homework assignment.

Thanks for posting again! We're glad you like this series. You will see more STL by STL. Also, you will see much more C++ content in the coming months - the language and tooling continue to evolve and Microsoft mind and muscle are firmly behind
helping to push the native stack forward.

And comparing the ref-counted deterministic resource management offered by shared_ptr vs. garbage-collector systems, are the performance of ref-counted systems better than those offered by GC?

I found this article in which there is a detailed comparison of resource management techniques, and in the "Performance" paragraph it seems to show that a tracing GC can offer better performance than a ref-counted system:

And, as a side question: does it exist a tracing garbage collector for C++? The language is so powerful that I think it could be possible to write one. So people could still enjoy the advantages of C++ (e.g. portability on different platforms, not requiring
download and installation of .NET framework, not wasting time for just-in-time compilation of code, etc.) and don't pay too much attention to memory allocation, cleanup, cycles, etc.

It is good to hear that C++ isn't dead at MS yet. The impression one tends to get just by viewing C9 is that if you aren't developing in WPF/Silverlight/XNA or other .Net technology, you might as well develop for other OSs. Enjoying this series. It has
been a way to get my coworkers to learn about and use STL where appropriate. Many of them are old-school C programmers who picked up C++/MFC as needed, but never really carried through with it as it has progressed. Thanks again.

C++ is not only not dying, but MS is pumping up the volume of the technology, from compilers to language and libraries and of course IDE enhancements and debuggers and builders (and linkers and....). This will become more obvious in the coming months. Bookmark
the above tag...

shared_ptr is heavier than a GC, but most things don't need to be manually allocated or shared so you should be using it so little that it doesn't matter.

I don't think it would be easy for a C++ GC to reach the performance of the .NET GC, because .NET is so much stricter about what you can do with an object, ie. there's nothing stopping me from holding a pointer to a member of an object and using an offset
to compute the actual object's address. I believe the .NET GC also defragments the heap, seems unlikely with C++.

[PhrostByte]> STL, I'm curious if you know why unique_ptr has array new/delete support but shared_ptr doesn't?

I'm not exactly sure. (I'm on the Standardization Committee's mailing lists, but I haven't attended their meetings.) There was some discussion of defining shared_ptr<T[]>, but it appeared to have been rejected as too controversial with insufficient implementation
experience. The strongest argument against it was that specializations should behave like the primary template (vector<bool> being an obvious offender), but shared_ptr<T[]> would actually be significantly different (it would have to prohibit derived-to-base
conversions, for example). Given that, it should be differently named instead of being a specialization. boost::shared_array exists, but was not incorporated into TR1/C++0x.

The biggest mystery to me is actually why unique_ptr<T[]> was retained, given the controversy with shared_ptr. There could be a rationale there, or it could be an oversight. (If there's a rationale, I'd guess that it's because unique_ptr is zero overhead,
so providing an array form could be useful to someone who needs a dynamically allocated array with a runtime length (std::array has a compiletime length), needs exception safety (owning raw pointers lead to leaktrocity), and doesn't need the flexibility and
doesn't want to pay the minor costs of std::vector (which is at least as large as three pointers). On the other hand, shared_ptr has overhead (minor, but nonzero). It is difficult for me to imagine a scenario in which shared_ptr<vector<T>> is unacceptable,
but shared_array would be acceptable.)

> And a slight correction: having the same initialism is fun, but shared_ptr etc. were not added to SGI's Standard Template Library, but to the C++ Standard Library.

Like most people, I use "STL" to refer to "the parts of the C++ Standard Library that were derived from or strongly influenced by Stepanov's original work". This usage doesn't lead to confusion. In that interpretation, shared_ptr is very clearly part of
the STL, while iostreams are not (and for std::string, flip a coin).

[Sys64738]> And comparing the ref-counted deterministic resource management> offered by shared_ptr vs. garbage-collector systems, are the> performance of ref-counted systems better than those offered by GC?

There's a major difference between universal refcounting and shared_ptr's refcounting. The vast majority of resources in a C++ program won't be managed by refcounting. For example, vector maintains no reference count. Its destructor simply deallocates its
memory (and any owned by its elements, recursively). Thanks to C++'s deterministic destruction, the compiler knows when to destroy vectors on the stack. A local vector's lifetime is known at compiletime, so tracking it is O(0). shared_ptr uses reference counting
to track the lifetimes of dynamically allocated objects, but it's certainly not the case that everything in a C++ program is held by shared_ptr.

The other major difference between C++'s resource management system and GC is that C++'s system is resource-agnostic, while GC isn't. C++ destructors don't care what they're destroying, and can be used to manage memory, files, sockets, locks, textures, fonts,
HWNDs, whatever equally. They don't care whether they're being invoked for local objects or dynamically allocated objects (vector elements, shared_ptr-owned objects, etc.) either. In contrast, non-deterministic GC handles memory much better than non-memory
resources. *Usually*, nobody will notice if you hang onto memory for longer than absolutely necessary. Hanging onto non-memory resources for longer than necessary is a big deal, though. Keeping a file open, holding onto a texture (in video memory!), etc. could
have observable and undesirable effects. (And "finalizers" are an incomprehensible nightmare.)

> And, as a side question: does it exist a tracing garbage collector for C++?

One of the goals of my videos is to demonstrate that C++ (uniquely!) can be used to write code that doesn't concern itself with the details of resource management, without falling into the tar pit that is universal GC. In fact, in Part 3 I drew big NO signs
around new/delete and new[]/delete[].

> I would have used simple C++ overload... but the template metaprogramming technique presented by STL is very cool!

As I mentioned, I was concerned that the template metaprogramming here consumed more effort than it saved, but I figured I'd demonstrate it anyways. (The N=2 of vector/deque and list/forward_list is really the worst case for simplifying code. When N=lots,
as with (unordered_)?(multi)?(map|set), the savings are clearer.)

> May some other lesson be dedicated to the template metaprogramming subject?

Template metaprogramming is relatively advanced, but I might use it in future installments.

(In an "Inside the STL" series, template metaprogramming would feature prominently, as it powers most of our ingenious tricks.)

PhrostByte: Yes, my reaction is very much "if you want .NET, you know where to find it".

Couldn't you've used the container traits defined in the std:: containers, instead of creating your own traits, to find out the type of container? I remember something about traits in Effective C++, but am not exactly sure anymore.

There aren't any container traits. Perhaps you're thinking of std::iterator_traits. In this case, iterator traits are not applicable, because both std::list and std::set have bidirectional iterators, but they have different erasure patterns.

I love these lectures, however exercise code at the beginning felt a bit disconnected from the topic. Too much too fast, especially when I only have basic grasp of templating (like, generics in C#). Otherwise, I want more

I had a question on your implementation of the homework assignment from part 2. When you used your container_traits classes was there a particular reason why you didn't just create an additional set of specialized classes to implement the specialized erase
methods? Was it just for simplicity of demonstration or is there a technical reason? I would think eliminating the need for the ignored argument would ultimately be a better solution since you wouldn't have to hope for an optimization by the compiler.

That's equivalent, but it's basically the same amount of code. (When there are two equivalent ways of saying something, I'll usually choose the shorter one.) I actually used to use static member functions of explicitly/partially specialized classes before
I began maintaining the STL, where Dinkumware's convention is to use overload resolution. If you like using specializations, go for it!

Note that because the helpers will be inlined, the compiler will easily be able to optimize out nameless empty arguments. It's okay to assume a basic level of competency on the optimizer's part.

I just finished filming Parts 4 and 5! They'll be making their way to you soon.

geeyef: When you dllexport T, the compiler has to generate its copy constructor and copy assignment operator immediately, because whoever's linking against your DLL might want to copy construct or copy assign T. This is different from how C++ ordinarily
works, where the copy constructor and copy assignment operator will only be generated when you attempt to use them for the first time.

vector<unique_ptr<int>> isn't copy constructible or copy assignable, because that would require copying its elements, which are non-copyable (but movable). Therefore, compilation fails. The compiler errors are saying this, but as usual they're hard to
understand if you're not an expert (and the compiler doesn't talk about the ultimate reason involving dllexport).

When you add a unique_ptr<int> data member, its copy ctor/copy assign are private and unimplemented. The compiler sees that they're private, and does not attempt to generate T's copy ctor/copy assign. vector<stuff> has a public copy ctor/copy assign, so
when it's the only data member, the compiler behaves differently (it's only when it tries to instantiate the copy ctor/copy assign that compilation explodes).

With vector<unique_ptr<int>> as the only data member, you can add this to make it compile:

private: T(const T&); T& operator=(const T&);};

That will prevent the compiler from attempting to generate a copy ctor/copy assign which will explode.

C4251 is essentially ignorable here. You should be aware that using the STL in your DLL's interface (as opposed to just its implementation) forces you to play by the STL's rules - in particular, mixing major versions is forbidden. You can't compile such
a DLL with VC10 and have somebody compiling with VC9 or VC11 link against it, because the STL intentionally breaks binary compatibility between major versions.

Loved the video.During unique_ptr, you mention that copy ctr is private, but returning from a function will work. I'm wondering if you could briefly explain the C++ mastery that's used to accomplish this.Thanks,...Matt

The problem with a shared pointer to a vector is that you have to dereference twice to get at the data, so what is really needed is a form of a vector featuring shared storage and reference counting; I would say not having this is an oversight.

My question at Installment 1 got drowned together with my comment it was in, and I would really like to know: STL is optimised for time, do you know a library optimised for space? I mean, get along with virtual functions but do not create the M*N*X implementations
effect.

As a related thought about safe destruction, observe that there is no object in the STL to safely hold a standard message catalogue.

Great series. These lectures are not only informative but the energy you show really has me delving into the STL. Being as though this is very new to me I have a request. In your example above (part of homework part 2) could you add/supply an example
of how to use the erase_if for an associative container (preferably map). Having difficulty getting the predicate correct.

so, to eliminate this exception, helper function move() taken into account for unique_ptr. But this may be highly expensive [consumes much CPU cycles] due to moving the entire elements [or chunk of memory] from one refernce pointer ot another.

However, shared_ptr can support copy constructor.

But is there any way to reference a memory object by a new pointer rather than moving the whole array from one pointer reference to new one. ?

Thank you very much for your spotlight.Really, Mr. Stephane i am a very big fan of yours...Hats off to an amazing and interesting coneptual facts.Thank you once again...

I vaguely remember you using a container<smart_ptr<type>> and using some sort of indirection comparator that would dereference the pointer. However, I can't seem to find a reference to it and it's not in any of the video descriptions. I don't want to spend 8-10 hour rewatching all these videos if possible.

Remove this comment

Remove this thread

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation,
please create a new thread in our Forums, or
Contact Us and let us know.