This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
libstdc++ debug mode ideas 5
- From: Benjamin Kosnik <bkoz at redhat dot com>
- To: libstdc++ at gcc dot gnu dot org
- Date: Wed, 6 Aug 2003 14:29:01 -0500
- Subject: libstdc++ debug mode ideas 5
Begin forwarded message:
Date: Wed, 30 Jul 2003 17:31:59 -0700
From: Doug Gregor <dgregor@apple.com>
To: Gabriel Dos Reis <gdr@integrable-solutions.net>
Cc: Benjamin Kosnik <bkoz@redhat.com>
Subject: Re: [libstdc++ PATCH] libstdc++ debug mode (second try)
On Wednesday, July 30, 2003, at 3:56PM, Gabriel Dos Reis wrote:
> 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.
Perhaps. But we need a renaming/aliasing mechanism with a finer
granularity than namespace aliasing (even with these extensions) gives
us. See below.
> | 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.
Won't work. There are certain components that _must_ be unchanged
regardless of whether we are in debug more or release mode. std::cin is
a major one: we can't have two std::cin's floating around, one from
__gnu_release and one from __gnu_debug, because they won't work well
together and we will break valid C++ programs. That one can be solved
with a using declaration (since it's just an object), but what about
std::basic_istream? It's in the type of std::cin, so it cannot change
regardless of whether or not we're in debug mode.
There's a reason that the debug wrapper for basic_string does not
replace std::basic_string when we're in debug mode. string's are
returned from virtual functions in locales, so if one were to attach a
facet compiled in release mode that expects to return a debug-mode
string, and that facet were used in a translation unit compiled in
release mode, it would die horribly. _Anything_ that affects the global
state _must_ be shared for valid C++ programs to run properly; anything
that needs to change for debug mode must be renamed/aliased so that
there is no ODR violation come link time.
I don't care if we call it renaming or aliasing, but it has to be at a
level of granularity where I can say "make __gnu_debug::vector look
like std::vector". Again, link_name has this granularity.
> | 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.
Just derive from something in namespace std.
> | 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.
Just derive from something in namespace std.
> 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).
FWIW, I have gone down this path before (that's why I listed it as #4
previously), and I just don't see any way it will work.
> | 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.
Looks like we have some miscommunication. My scheme does _not_ have any
inclusion order dependencies, and it is quite simple:
#include<debug/vector> gives you a debugging vector named
__gnu_debug::vector (doesn't matter whether you're in debug or release
mode)
#include <vector> gives you a vector named std::vector (in debug mode,
it's a debugging vector; in release mode, it's a release-mode vector)
I'm having a hard time seeing much benefit to turning all vectors into
debugging vectors for a particular translation unit without just
applying -D_GLIBCXX_DEBUG to turn all containers into debug containers.
Can you imagine a use-case for this behavior? For reference, we needed
precisely the functionality I proposed: there was some real strangeness
with one of our std::map instances, and we could easily have caught it
by changing it to __gnu_debug::map (this is what triggered the
feature).
> | > 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
Two questions, then:
1) What are the strong arguments for per-container-basis (as opposed
to per-instance-basis) selection?
2) What would this compiler magic look like?
Doug