This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

libstdc++ debug mode ideas 4



Begin forwarded message:

Date: 31 Jul 2003 00:56:59 +0200
From: Gabriel Dos Reis <gdr@integrable-solutions.net>
To: Doug Gregor <dgregor@apple.com>
Cc: Benjamin Kosnik <bkoz@redhat.com>
Subject: Re: [libstdc++ PATCH] libstdc++ debug mode (second try)


Doug Gregor <dgregor@apple.com> writes:

| On Wednesday, July 30, 2003, at 10:21AM, Gabriel Dos Reis wrote:
| > | The fact is that, in the absence of a perfect template aliasing
| > model,
| > | compiling part of a program in release mode and part of it in debug
| > | mode is an ODR violation. If you agree with this, then I only see two
| > | options:
| > | 	(1) Find that perfect template aliasing model, or
| > | 	(2) Manage the ODR violation so that it can't cause trouble.
| >
| > I do not think it is a template aliasing model and that finding that
| > template alising model makes the problem (if there is one) go away.
| >
| > The template-name is primarily there to provide name commonality.
| > What is being violated is not the declaration of the template-name,
| > but the ODR for the entity being named by the template.
| 
| I think a perfect template aliasing model would make the problem go
| away because we could do this:

The point of my previous note is that the debug thingy does not just
concern templates.  It concerns also normal classes/functions.  The
thing you're after is a renaming mechanism, not a template aliasing
mechanism. A template aliasing mechanism will just solve a tiny part of
the whole thing.  It will miss the big picture.  I would not advise 
going that road.

| namespace std {
|    namespace __release {
|      template<typename T, typename Allocator = std::allocator<T> >
|        class vector; // define release-mode vector
|    }
|    namespace __debug {
|      template<typename T, typename Allocator = std::allocator<T> >
|        class vector; // define debug-mode vector
|    }
| }

Suppose we have a referencing construct, which in an imginary syntax
does the following

  namespace __gnu_release { }

  namespace __gnu_debug { }

  using std = _GLIBCXX_DEBUG ? __gnu_debug : __gnu_release;

and after that you can reopen std:: as if it were an original
namespace -- i.e. not a namespace-alias according to standard text. 
Then, I believe you'll be saved away from many troubles.

| Then, we add some directive that makes std::vector alias
| std::__release::vector (when we're in release mode) or
| std::__debug::vector (when we're in debug mode). A using declaration
| very nearly gets us there, except that it breaks specialization:
| 
| namespace std {
| #ifdef _GLIBCXX_DEBUG
|    using __debug::vector;
| #else
|    using __release::vector;
| #endif
| }

Sometime ago (meaning ~1999), I thought about that sort of thing --
for hiding some of our implementation details.  I think I abandoned the
idea because of some name lookup issues.  I'll have to rethink about
it to remember the details. 

|   I think your template aliasing proposal would let us do this:
|
| namespace std {
| #ifdef _GLIBCXX_DEBUG
|    template<typename T, typename Allocator=std::allocator<T> >
|      using vector = __debug::vector<T, Allocator>;
| #else
|    template<typename T, typename Allocator=std::allocator<T> >
|      using vector = __release::vector<T, Allocator>;
| #endif
| }

But it will not work well with Koenig lookup because the alias
std::vector will resolve to the original templates and I'm worrying
about  simple non-debuged functions like std::swap.

The scheme I outlined above does not have that problem -- it does not
have mangling problem either (it acts like a "reference" to the
original namespace).

| > | 	I see that include <debug/vector> makes std::vector the debug
| > | version even if we are compiling in release mode.
| >
| > I must confess my sympathy for this approach.  It is the most simple
| > semantics I would expect.
| 
| Okay. We're trading off the ability to easily switch a particular
| container instance to debug mode (e.g., by changing std::vector<...>
| to __gnu_debug::vector<...> in the source) with the ability to change
| all containers to debug versions (e.g., by including <debug/vector>
| instead of <vector>). 

Yes, I acknowledge that.  However the kind of selection you're
proposing comes with many complications, starting with inclusion order
dependency.  I do not believe in that approach.  Rather, I think a
per-translatin-unit basis selection is smoother and cleaner. 

| I personally think the former is more important,
| because I suspect that users would prefer to debug programs that
| crash, say, after an iterator dereference by turning debugging on only
| for a few suspect container instances and compiling only a little
| code. The <debug/vector> model will turn on debugging for a lot more
| container instances, and I wonder how much use it would get vs. just
| turning on _GLIBCXX_DEBUG.
| 
| > | This differs from my
| > | original patch, where <debug/vector> declares a debugging vector as
| > | __gnu_debug::vector (regardless of whether or not we're in debug
| > | mode). The benefit of your approach is that users can change one
| > | #include to get debugging for a certain container type; the
| > | disadvantage is that you can't change it for a single container
| > | instance (since there is no separate __gnu_debug::vector to use). The
| > | other issue is that
| > |
| > | 	#include <vector>
| > | 	#include <debug/vector>
| > |
| > | will fail to compile in release mode, because std::vector will be
| > | defined twice and __std::vector will not be defined at all. With this
| > | methodology, the best we could do would be to emit a warning that the
| > | debug-mode vector will _not_ be used, and then skip the debug
| > | version. I wonder how many users would leave a stray <debug/vector>
| > | somewhere in their program and wonder why things are running slowly.
| >
| > I think we should simply take that, we should avoid inclusion order
| > dependency and we should avoid second-guessing the programmer, by
| > assuming that he is stupid.  I'm not sure how we can reconsile the
| > above criteria but I will certainly object to changing the semantics
| > behind the back of the user.
| 
| Any idea on how we can avoid the inclusion-order dependencies? If we
| see both <debug/vector> and <vector>, so we always pick the debug
| version? The release version? AFAICT, we're stuck with the first one
| that's included (because it defines std::vector), and I think that's a
| bit confusing.

I do see those as strong arguments against per-container-basis
selection.  Rather, I prefer to rely on the compiler, which in -debug
mode, will take care of doing the right magic.  It offers a unified
view and is easily explained and implemented.

-- Gaby


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]