C/C++ Contributing Editors


Uncaught Exceptions: The Spiral Dance

Bobby Schmidt

A New Hope: C++Ox is coming, and the Empire seems to be listening.


Copyright © 2002 Robert H. Schmidt

In my January column, I lamented the premature death of my Microsoft C# project and portended the resulting end of my Microsoft writing career. I also hinted that I might bail on my CUJ career as well.

Immediately after finishing that column I spent four weeks alone, driving through deserts and mountains and along the sea. As I indicated in that column, I had hoped the trip would bring much needed clarity. Well I got that clarity, and more: several transcendent experiences, one of which bordered on X-Files reality [1].

I returned to find positive change within Microsoft, change that has reinvigorated my commitment to the company and resurrected my writing career all around. Although I could consume an entire column with this topic, I will but summarize here:

To that end I am resurrecting my MSDN column “Deep C++,” which has lain dormant since late 2000. By the time you read this, I should have been back on the air for at least a couple of months [3]. I’ll split my topics between Microsoft-specific extensions to C++ — especially those related to managed code in the .NET Framework — and the new Standard-conformance features.

Concerning the Latter...

Many “Uncaught Exceptions” items are really Visual C++ problems masquerading as Standard C++ problems. Such items fall into a clichéd pattern:

Q

When I try the following code from (take your pick: my column, a book, a class, Usenet, Dr. Meyers’ latest harangue), I get the following error from Visual C++...

A

Your sample should work according to both my interpretation of the C++ Standard and the results of my non-Microsoft translators in their Standard-conformance mode. The behavior you see is either “standard” Visual C++ and intentional, or a non-conformance bug. Here is what I think is happening plus some possible solutions...

As have many of you, I long ago dismissed Visual C++ as a serious Standard C++ compiler. I reckoned that Visual C++ was a mostly proprietary dialect of real C++, and that deep down Microsoft didn’t really care about conformance, regardless of public posture.

All of that is about to change.

In my recent dealings with the Visual C++ team, I’ve come to know their new and genuine commitments:

I invite doubters to read Herb’s first significant interview as C++ community liaison [4]. I also invite you to check out the first installments of my resurrected “Deep C++” column, where I plan to discuss the upcoming conformance changes in more detail. Once these changes appear in a publicly available compiler, I’ll start writing about them in CUJ as well.

Oh yeah, one more thing: I’m not leaving CUJ. Well, not completely — I’ve cut back to every other month, which I find a happier and more sustainable pace.

Competitive EDGe

Q

Bobby,

I was going through a CUJ article by you from October 2001. In the section called “Circular Breathing,” you mention running code through the Edison Design Group C++ front end to validate it. I checked out their website, and it makes no mention of any end-user products. Is there a way you know of to get just the front end for code analysis?

I’m on a project to apply some sort of objective quality metric to two-three million lines (depending on how you count) of Windows code. Evidently the contractors walked out in mid-project. Is EDG something that would be useful? Or would something else be more appropriate?

Thanks — Ed Fisher

A

I’ve long written about EDG’s C++ front-end translator without specifying what that translator is and how to get it. Thanks for prodding me to address my chronic vagueness.

EDG doesn’t sell an end-user commercial C++ product as such. They instead license their C++ front end to compiler vendors and other resellers. You can find a list of such resellers on their website [5].

The front end I use is what EDG calls a “demo” version. Its capabilities, while constrained, are enough to test and validate Standard conformance. The particular demo version I use runs only in Windows, generates intermediate C code, and requires that intermediate code to be built by Visual C++.

The demo doesn’t ship with a complete run-time library. When I’ve tried to use the Dinkumware library that ships with Visual C++, I’ve met mixed success — hardly surprising, given that the library is tuned to Microsoft’s implementation of C++, not EDG’s. Fortunately Dinkumware also sells a library tuned to the EDG implementation. P.J. Plauger has graciously provided me with what he calls a “writer’s copy” of that library [6].

I use the EDG translator to validate two things:

If you are looking to see how conformant your mega lines of code are, a compiler based on the EDG front end will help. But if you define your quality metric as something other than conformance, I don’t know that the front end will tell you much.

It’s a long long long long World

Q

Hello Bobby,

I understand the C language was recently re-standardized. When is the next time C++ will be re-standardized?

In my opinion, the naming convention for C++ intrinsic data types is somewhat limiting, and as platforms get bigger (requiring larger data types) the C++ intrinsic names get more obscure.

For example:

I’m currently working on a game for Playstation 2, where a common intrinsic data type is __int128.

The point I’m trying to make is that (in my opinion) C++ is in desperate need of a better naming convention for intrinsic data types. Also, the naming convention needs to support new data types for new (bigger) CPUs.

For portability, the team I’m working with has typedefed all the intrinsic data types with the following convention:

and so on through s256 and u256.

Sincerely — Tony Clifton

A

C++ is being “re-standardized” now, in the sense that the committee is entertaining changes and extensions. I believe the Standard is frozen for five years after its 1998 adoption, which means next year is the earliest that any changes can actually occur. Since we optimistically assume the next version will see life before 2010, we call this version C++0X. (This is the same shorthand we used for C99, which we called C9X before its adoption.)

I agree that the current naming scheme for C and C++ fundamental types does not scale well. That we are now resorting to names such as long long and long double betrays the stress we’re placing on that scheme.

If there is to be a solution, I believe it will lie in the library rather than the language. The C99 Standard library offers a model in <stdint.h> with typedefs of the form:

where N is the number of bits. The header also defines collateral symbolic constants:

along with their signed _MIN partners.

I expect these types, or close variants, to appear in the std namespace for C++0X. I’m not alone in this expectation: in his online CUJ column describing the “new” C++, Herb Sutter discusses the likely inclusion of <stdint.h> [7].

Even if we’re right, the solution will be incomplete, as it doesn’t cover character and floating-point types. Whether this limitation even matters is something the committee members will have to sort out. People I’ve seen devising similar schemes apparently care only about int types, so perhaps <stdint.h> is good enough.

Choosing Friends Wisely

Q

Hello,

I was recently asked to port some code from HP/UX to AIX. When compiling the enclosed sample on AIX with the IBM VisualAge 5.0 compiler, I get a puzzling error:

The "private" member "X::f()" cannot be accessed.

I searched for this error message on the support groups and found an answer from IBM technical support. They claim the behavior is correct according to the C++ Standard. They quoted Subclause 11.4/7:

claiming that was consistent with the definition of access control in Subclause 11/1:

Earlier versions of the IBM compiler, HP/UX’s native compiler, Visual C++, and gcc all have no problem with this code fragment. This made me curious as to the other compilers’ interpretation of the Standard. Is IBM being unfairly strict? Was this an intended interpretation of the Standard? (I’m restricted to the fragments IBM quoted, as I don’t have a copy.)

It seems odd to me that I should need to promote a private method into a class’s public interface for the sole purpose of having its symbol made visible to a friend nomination. The friend statement in my class Y is not attempting to access the symbol f, but is instead attempting to nominate f as a friend.

I guess I’m just looking for your take on this.

Thanks — Ron Hume

A

My version of your code sample is:

class X
    {
private:
    void f();
    };

class Y
    {
    friend void X::f(); // error here
    };

Of the three compilers I have installed:

My normal temptation is to believe EDG and press on. Their interpretation and IBM’s support a simple rule: the names of a class’s private members are available only to other members and friends of that class, regardless of what you do with those names.

But that rule does seem harsh in light of what you want to do with the name: grant the name’s correlative entity friendship. That doesn’t harm the friend, or otherwise give you access to the friend. If anything, it potentially harms you if the friend misbehaves.

Within the C++ Standard Committee, the Council of Language Elders (a.k.a. the Core Language Working Group) pondered this very problem [8]. Their conclusion: the verbiage in 11.4/7 is defective and does not reflect the committee’s intent. They voted to remove the sentence IBM cites (“A name nominated...”).

Or so they thought.

Upon further deliberation, the Elders uncovered a dark truth: removing this sentence would cause a cascade reaction through other passages requiring clarification or deletion, thereby risking destruction of the entire Death Star, er, Standard.

Consider the variation:

class X
    {
private:
    struct S; // new
    S f();    // changed
    };

class Y
    {
    friend X::S X::f(); // Well?
    };

which accesses both the private function f and the private type S. Should this work? Is S implicitly given friendship?

Or worse, consider:

class X
    {
private:
    struct S;
    friend void f(); // changed
    };

class Y
    {
    friend void f()
        {
        X::S *p; // er, um...
        }
    };

The friend declaration in X gives global function f access to X’s private pieces, including S. The friend declaration in Y is for the same global f. That second declaration also defines f.

Should the private pieces of X be accessible in the body of f when that body appears in Y? Would your answer change if Y were also a friend of X?

Unable to contain the defect report’s terrible power, the Elders finally cast it into the fires of Mordor. From their rationale:

(“One Standard to rule them all...”)

So there you have the official ruling: Not a Defect by Reason of Inexplicability. The Elders apparently wanted to make private friends work, but couldn’t figure out how to articulate that in the Standard without breaking something else. (Hmm, sounds just like a software project.)

One side effect is that all of our compilers are right:

Inaccessible and overly private friends are a nuisance, in real life and elsewhere. If you care about portability, I suggest you avoid the whole ruckus: don’t grant friendship to private entities, regardless of which “right” behavior your compiler supports. If you simply can’t help yourself, then grant friendship to the class containing the private entity:

class X
    {
private:
    void f();
    };

class Y
    {
    friend class X;
    };

Now the private f can mess around with the internals of Y, as you originally intended.

Accepting Excepting

Q

Hello,

How do I declare pointers to functions throwing exceptions?

Thank you and good day. — “sathya tn”

A

Based on other parts of your email, I’m assuming what you’re really after is how to preserve an exception specification as part of a function pointer.

In the simple case of:

void f() throw(int);

you can declare a pointer to f via:

void (*pe)() throw(int);
pe = f; // OK

Mysteriously, the language rules won’t let you tidy this up with a typedef:

        void (*pe)() throw(int); // OK, but...
typedef void (*PE)() throw(int); // error
typedef void (*P) ()           ; // OK

And no, I don’t know why this is. Maybe the typedef grammar can’t be precisely extended this way. (See fires of Mordor, above.)

In this context, exception specifications are like const qualifiers in reverse. With const qualification, you can convert from less restrictive to more, but not visa versa:

void *p;
void const *pc;

pc = p; // OK,    gains restriction
p = pc; // error, loses restriction

With exception specifications, the reverse is true:

void (*p)();
void (*pe)() throw(int);

pe = p; // error, gains restriction
p = pe; // OK,    loses restriction

This conversion rule implies that you could store the address of f in a pointer lacking an exception specification:

void f() throw(int);

void (*p)();
void (*pe)() throw(int);

p = f;  // OK, loses restriction
pe = f; // OK, same  restriction

If f were declared without a specification, the results would change:

void f(); // no specification

...

p = f;  // OK,    same  restriction
pe = f; // error, gains restriction

I suspect that many of you have never before seen exception specifications on pointer declarations or were even aware such things are possible. They could also be new to your compiler vendor. Of my compilers:

Notes

[1] No, I won’t tell you what it was, so don’t ask! All I’ll say is that it came in the desert outside Blythe, CA, near where I set up for the spectacular Leonid meteor storm.

[2] I was Sara’s new-hire mentor when she first joined Microsoft’s Developer Support.

[3] <http://MSDN.Microsoft.com/columns/DeepC.asp>

[4] <http://www.CodeProject.com/interview/HerbSutter3032002.asp>

[5] <www.EDG.com/resellers.html>

[6] I don’t know that the Visual C++ library cannot or ought not work. It could well be that it does work, but I’m missing some secret. Admittedly I haven’t tried too hard, since Dinkumware’s other library version suffices.

[7] <www.cuj.com/experts/2004/sutter.htm>

[8] <http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_closed.html#209>

[9] Sad but true: the Visual C++ v7 compiler still doesn’t call std::unexpected or enter an unexpected_handler when a function violates its specification. See my column preamble for future hope.

Although Bobby Schmidt makes most of his living as a writer and content strategist for the Microsoft Developer Network (MSDN), he runs only Apple Macintoshes at home. In previous career incarnations, Bobby has been a pool hall operator, radio DJ, private investigator, and astronomer. You may summon him on the Internet via BobbySchmidt@mac.com.