Exception Specifications

Discussion in 'C++' started by Stuart Golodetz, Sep 23, 2006.

  1. Hi all,

    Just wondering whether there's any reason why exception specifications are
    enforced at runtime, rather than at compile-time like in Java? (This was
    prompted by reading an article on GOTW, incidentally.) Is there something
    about C++ that makes it harder/impossible to check at compile-time?

    Cheers,
    Stu
    Stuart Golodetz, Sep 23, 2006
    #1
    1. Advertising

  2. Stuart Golodetz wrote:

    > Just wondering whether there's any reason why exception specifications are
    > enforced at runtime, rather than at compile-time like in Java?


    Beacause is a loose of time. I've seen plenty of Java code samples full of:

    try something; catch anything required by the specification: Do nothing;

    --
    Salu2
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Sep 23, 2006
    #2
    1. Advertising

  3. "Julián Albo" <> wrote in message
    news:...
    > Stuart Golodetz wrote:
    >
    >> Just wondering whether there's any reason why exception specifications
    >> are
    >> enforced at runtime, rather than at compile-time like in Java?

    >
    > Beacause is a loose of time. I've seen plenty of Java code samples full
    > of:
    >
    > try something; catch anything required by the specification: Do nothing;
    >
    > --
    > Salu2


    Whether exception specifications are a good thing or not is certainly up for
    discussion :) What I don't understand though is what purpose is served by
    enforcing them at runtime. If you're going to enforce them, surely it should
    be at compile-time? I was just wondering if there's some technical
    difficulty making that impossible, or at any rate very hard?

    Cheers,
    Stu
    Stuart Golodetz, Sep 23, 2006
    #3
  4. Stuart Golodetz

    peter koch Guest

    Stuart Golodetz skrev:

    > "Julián Albo" <> wrote in message
    > news:...
    > > Stuart Golodetz wrote:
    > >
    > >> Just wondering whether there's any reason why exception specifications
    > >> are
    > >> enforced at runtime, rather than at compile-time like in Java?

    > >
    > > Beacause is a loose of time. I've seen plenty of Java code samples full
    > > of:
    > >
    > > try something; catch anything required by the specification: Do nothing;
    > >
    > > --
    > > Salu2

    >
    > Whether exception specifications are a good thing or not is certainly up for
    > discussion :) What I don't understand though is what purpose is served by
    > enforcing them at runtime. If you're going to enforce them, surely it should
    > be at compile-time? I was just wondering if there's some technical
    > difficulty making that impossible, or at any rate very hard?


    I believe it is hard. Consider:

    std::vector<int> v;
    .....

    int i = v.size() > 0? v.at(0):0;
    Should that statement be assumed to throw or not?
    While it is easy for us to see, it is more difficult for a compiler.
    And it can be made even more difficult if v.at(0) is replaced by a
    function-call with v as a parameter. I believe you can see the point?

    /Peter

    >
    > Cheers,
    > Stu
    peter koch, Sep 23, 2006
    #4
  5. Stuart Golodetz wrote:

    >> try something; catch anything required by the specification: Do nothing;


    > Whether exception specifications are a good thing or not is certainly up
    > for discussion :) What I don't understand though is what purpose is served
    > by enforcing them at runtime. If you're going to enforce them, surely it
    > should be at compile-time?


    As shown by my sample, checking it at compile time does not enforce
    anything. When people see a message from the compiler, immediately add code
    like this. Or instead of doing nothing they abort the program, thus
    effectively doing the check at runtime but having to write code to do it.

    Surely C++ compilers can add a check and issue a warning when explicit
    violations of the specification are detected, the reason they not do it is
    that almost anybody wants it.

    > I was just wondering if there's some technical difficulty making that
    > impossible, or at any rate very hard?


    People habitually don't add features or options to a compiler, or any other
    program of certain size and complexity, just because there is not
    impossible or very hard to do it. They do it when the authors think, or a
    bunch of users tell him, that it will be useful.

    If you are talking about the language standard, not the features of concrete
    compilers, I suggest you to read "The design and evolution of C++".

    --
    Salu2
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Sep 23, 2006
    #5
  6. peter koch wrote:

    > I believe it is hard. Consider:
    >
    > std::vector<int> v;
    > ....
    >
    > int i = v.size() > 0? v.at(0):0;
    > Should that statement be assumed to throw or not?


    By the point of view of checking specifications is easy: the statement can
    throw if and only if vector::size or vector::at can throw.

    > And it can be made even more difficult if v.at(0) is replaced by a
    > function-call with v as a parameter. I believe you can see the point?


    In that case, the specification of that function is checked, same difficult.

    --
    Salu2
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Sep 23, 2006
    #6
  7. Stuart Golodetz

    Jens Theisen Guest

    "Stuart Golodetz" <> writes:

    > Whether exception specifications are a good thing or not is certainly up for
    > discussion :) What I don't understand though is what purpose is served by
    > enforcing them at runtime. If you're going to enforce them, surely it should
    > be at compile-time? I was just wondering if there's some technical
    > difficulty making that impossible, or at any rate very hard?


    I disagree with the other answers to your question - I find exception
    specifications almost useless for that reason; and in practice, indeed
    most people don't use them. To quote Herb Sutter:

    'In brief, don't bother with exception specifications. Even experts
    don't bother.'

    And the boost coding guidelines discourage using them either.

    There are some minor uses for them that have to do with optimisations
    a compiler can do when he knows that exceptions can't occur, but they
    are really unusable for what they are for in language like java: To
    document what functions throw and enforce this documenation.

    If someone know why exception specifications are as brain-dead as they
    are in C++, I'd be intruiged to hear. My guess is some compatibility
    rationale.

    Jens
    Jens Theisen, Sep 23, 2006
    #7
  8. Stuart Golodetz

    Bo Persson Guest

    Julián Albo wrote:
    > peter koch wrote:
    >
    >> I believe it is hard. Consider:
    >>
    >> std::vector<int> v;
    >> ....
    >>
    >> int i = v.size() > 0? v.at(0):0;
    >> Should that statement be assumed to throw or not?

    >
    > By the point of view of checking specifications is easy: the
    > statement can throw if and only if vector::size or vector::at can
    > throw.


    But vector::size doesn't throw, and vector::at isn't called if the
    condition is such that it could throw. So is this statement throwing
    or not? Can the compiler detects that?

    >
    >> And it can be made even more difficult if v.at(0) is replaced by a
    >> function-call with v as a parameter. I believe you can see the
    >> point?

    >
    > In that case, the specification of that function is checked, same
    > difficult.


    The other problem is with templates, where the throw spec really
    depends on the template parameter

    template<class T>
    void do_something(T x); // might throw for some Ts

    How do we express that?


    Bo Persson
    Bo Persson, Sep 23, 2006
    #8
  9. Bo Persson wrote:

    >>> int i = v.size() > 0? v.at(0):0;
    >>> Should that statement be assumed to throw or not?

    >>
    >> By the point of view of checking specifications is easy: the
    >> statement can throw if and only if vector::size or vector::at can
    >> throw.

    >
    > But vector::size doesn't throw, and vector::at isn't called if the
    > condition is such that it could throw. So is this statement throwing
    > or not? Can the compiler detects that?


    What compiler? Maybe a compiler that does it can be written, at least for
    standard functions with well defined behavior, but I don't think there is a
    great demand for such feature. By the way, in this example you can drop
    'at' and use operator [ ] instead.

    > The other problem is with templates, where the throw spec really
    > depends on the template parameter
    > template<class T>
    > void do_something(T x); // might throw for some Ts
    > How do we express that?


    I suppose that a compiler that check the specifications at compile time
    'java style' will check at complete specialization of the template time.
    Supposing that such compiler will exist any time. One can imagine a
    sintaxis to express something as: "can throw what T::somefunc throws", but
    I suspect that such complications will never be used by any programmer.

    --
    Salu2
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Sep 23, 2006
    #9
  10. Stuart Golodetz

    Jerry Coffin Guest

    In article <>,
    Em says...
    > Hi all,
    >
    > Just wondering whether there's any reason why exception specifications are
    > enforced at runtime, rather than at compile-time like in Java? (This was
    > prompted by reading an article on GOTW, incidentally.) Is there something
    > about C++ that makes it harder/impossible to check at compile-time?


    The following is based primarily on recollection, so it may need to be
    taken with a grain of salt.

    In a phrase, backward compatibility. Exception specifications were added
    to C++ after there were a number of implementations of exception
    handling. These were consistent enough that it was considered reasoanble
    and important to maintain compatibility with them. To maintain
    compatibility with this code, the rule was made that lack of an
    exception specification meant "can throw anything."

    Unfortunately, that also meant that essentially all existing code was
    seen (by the compiler) as being able to throw anything -- even pure C
    code that had no notion of exception handling at all.

    If exception specifications were enforced at compile time, new code that
    used them would have had to do one of two things: either rewrite all
    existing code to include exception speciifications (incidentally,
    breaking all C compatibility) or else include a 'catch(...)' clause in
    the new code to catch and convert the (probably nonexistent) "other"
    exceptions to something it was allowed to throw.

    Neither of these was seen as acceptable, leaving run-time enforcement as
    nearly the only possible solution.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Sep 23, 2006
    #10
  11. "Jerry Coffin" <> wrote in message
    news:...
    > In article <>,
    > Em says...
    >> Hi all,
    >>
    >> Just wondering whether there's any reason why exception specifications
    >> are
    >> enforced at runtime, rather than at compile-time like in Java? (This was
    >> prompted by reading an article on GOTW, incidentally.) Is there something
    >> about C++ that makes it harder/impossible to check at compile-time?

    >
    > The following is based primarily on recollection, so it may need to be
    > taken with a grain of salt.
    >
    > In a phrase, backward compatibility. Exception specifications were added
    > to C++ after there were a number of implementations of exception
    > handling. These were consistent enough that it was considered reasoanble
    > and important to maintain compatibility with them. To maintain
    > compatibility with this code, the rule was made that lack of an
    > exception specification meant "can throw anything."
    >
    > Unfortunately, that also meant that essentially all existing code was
    > seen (by the compiler) as being able to throw anything -- even pure C
    > code that had no notion of exception handling at all.
    >
    > If exception specifications were enforced at compile time, new code that
    > used them would have had to do one of two things: either rewrite all
    > existing code to include exception speciifications (incidentally,
    > breaking all C compatibility) or else include a 'catch(...)' clause in
    > the new code to catch and convert the (probably nonexistent) "other"
    > exceptions to something it was allowed to throw.
    >
    > Neither of these was seen as acceptable, leaving run-time enforcement as
    > nearly the only possible solution.
    >
    > --
    > Later,
    > Jerry.
    >
    > The universe is a figment of its own imagination.


    Hmm :) Assuming your recollection is accurate, it does make a fair amount of
    sense. It's a tad unfortunate that it went that way, though. Oh well, I
    suppose we'll just have to make do without using exception specifications.
    Thanks for the explanation, anyhow.

    Cheers,
    Stu
    Stuart Golodetz, Sep 23, 2006
    #11
  12. Stuart Golodetz

    Jerry Coffin Guest

    In article <>,
    Em says...

    [ ... ]

    > Hmm :) Assuming your recollection is accurate, it does make a fair amount of
    > sense. It's a tad unfortunate that it went that way, though. Oh well, I
    > suppose we'll just have to make do without using exception specifications.


    I originally thought it was unfortunate, but I've changed my mind. I've
    since become convinced that exception specifications (at least as
    currently defined) are a fundamentally mistaken design that runs
    directly counter to the intent and usefulness of exception handling in
    the first place.

    One of the basic ideas of exception handling is that the code that
    detects a problem rarely has the context to deal appropriately with that
    problem -- and in fact, the two will be separated by some arbitrary (but
    often large) distance both conceptually and in the call chain. One of
    the primary advantages of exception handling is that it allows the
    intermediate levels in that call chain to ignore all but those
    exceptions can (at least help to) handle. Other than that, their sole
    obligation is to be written in an exception-safe fashion.

    Exception specifications directly violate that, however. Instead of
    allowing all the intermediate levels to ignore all but the exceptions to
    which they can contribute handling, exception specifications demand that
    all the software, at all the intermediate layers, excplicitly know and
    acknowledge _all_ of the exceptions that might orignate from anything
    they might call. This is not merely impractical, but negates much (if
    not most) of the advantage exception handing provides in the first
    place.

    I believe virtually nobody really even _wants_ this. What they really
    want isn't an assurance that every level in a call chain is aware of all
    the exceptions that may originate down the call chain. Rather, the want
    an assurance that some code at SOME level in the call chain knows how to
    handle all of the exceptions that may happen in whatever it calls. If we
    could do THAT at compile time (or more likely link time, since it needs
    a view of the program as a whole) it would probably be truly worthwhile.

    Exception specifications wouldn't really be very helpful in that though.
    To enforce this at compile time, we'd basically start from the lowest
    level in a particular call stack, and put together a list of all the
    exceptions that can be thrown from that level. We'd then take a step up
    the call stack, and add in all the exceptions that level can throw, and
    so on. At each level we'd also look for any exception handlers, and
    examine their contents to see what exceptions that came from below would
    be caught at that level. We'd have to look at the contents of the
    handler to see whether it re-throws the current exception. Those that
    are caught but not re-thrown could be subtracted from the list of
    possible exception. Of course, the compiler would also have to take
    inheritance into account -- catching a base class obviously catches all
    derived classes.

    If there are any exceptions left in the list when we've looked at any
    exception handlers in main, these are exceptions that can be thrown but
    never caught. Being able to give at least a warning for that situation
    would almost certainly be useful. The difficult part of this analysis
    would probably be intermediate catch blocks that might only re-throw an
    exception conditionally -- and if the condition related to the type of
    the exception, it could be difficult to sort out which exceptions that
    were caught mnight be re-thrown and which never would.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Sep 24, 2006
    #12
  13. Stuart Golodetz

    Dave Steffen Guest

    "Stuart Golodetz" <> writes:

    > "Jerry Coffin" <> wrote in message
    > news:...
    > > In article <>,
    > > Em says...
    > >> Hi all,
    > >>
    > >> Just wondering whether there's any reason why exception
    > >> specifications are enforced at runtime, rather than at
    > >> compile-time like in Java?

    [...]
    > > Neither of these was seen as acceptable, leaving run-time enforcement as
    > > nearly the only possible solution.


    > Hmm :) Assuming your recollection is accurate, it does make a fair
    > amount of sense. It's a tad unfortunate that it went that way,
    > though. Oh well, I suppose we'll just have to make do without using
    > exception specifications. Thanks for the explanation, anyhow.


    One other issue, though: exception specifications are IIRC nearly
    impossible to deal with correctly when writing templates. You don't
    know, when writing the template (either function or class) what
    operations on the templated type may or may not throw, nor do you
    know what do to with them. I don't think anybody's come up with a
    good way for templates and exception specs to play nicely together.

    ----------------------------------------------------------------------
    Dave Steffen, Ph.D.
    Software Engineer IV Disobey this command!
    Numerica Corporation - Douglas Hofstadter
    dgsteffen at numerica dot us
    Dave Steffen, Sep 25, 2006
    #13
  14. Stuart Golodetz

    Geo Guest

    Stuart Golodetz wrote:
    > Hi all,
    >
    > Just wondering whether there's any reason why exception specifications are
    > enforced at runtime, rather than at compile-time like in Java? (This was


    C++ is NOT Java, why would you even hope that it might work the same,
    especially since Java exception handling is horrible, at least C++'s is
    so broken that it is unusable (in fact it is dangerous to use it), and
    therefore you never neeed to worry about it.

    > prompted by reading an article on GOTW, incidentally.) Is there something
    > about C++ that makes it harder/impossible to check at compile-time?
    >
    > Cheers,
    > Stu
    Geo, Sep 25, 2006
    #14
  15. On 25 Sep 2006 09:17:22 -0700, "Geo" <> wrote:
    >C++ is NOT Java, why would you even hope that it might work the same,
    >especially since Java exception handling is horrible, at least C++'s is
    >so broken that it is unusable (in fact it is dangerous to use it), and
    >therefore you never neeed to worry about it.


    Neither is Java exception handling 'horrible' (it's just different
    from C++) nor are C++ exception specifications 'broken'. WRT to the
    latter you propagate the widespread 'Stroustrup-had-a-bad-day' myth.
    It declares that everything in the C++ language is fine (more or
    less), just exception specifications are 'broken' and 'unusable'. The
    same article is usually quoted as reference.
    It's true that C++ exception specifications are not standardized in
    the most practical way (they are not even standardized as Stroustrup
    describes them in his book). But they are not more 'broken' than other
    C++ language elements like templates or the look-up rules.
    Exception specifications make sense for at least 2 use cases:
    1. you guarantee that no exception is thrown form a (usually low
    level) function. This eg. is important to implement assignment
    operators.
    2. you guarantee that the specified and only the specified
    exception(s) is(are) thrown from a function. Since exception
    specifications are part of the contract between the user and you, the
    implementer, all high level library interfaces should explicitly
    specify exceptions in code.

    Best regards,
    Roland Pibinger
    Roland Pibinger, Sep 25, 2006
    #15
  16. Stuart Golodetz

    Bart Guest

    Roland Pibinger wrote:
    > On 25 Sep 2006 09:17:22 -0700, "Geo" <> wrote:
    > >C++ is NOT Java, why would you even hope that it might work the same,
    > >especially since Java exception handling is horrible, at least C++'s is
    > >so broken that it is unusable (in fact it is dangerous to use it), and
    > >therefore you never neeed to worry about it.

    >
    > Neither is Java exception handling 'horrible' (it's just different
    > from C++) nor are C++ exception specifications 'broken'. WRT to the
    > latter you propagate the widespread 'Stroustrup-had-a-bad-day' myth.
    > It declares that everything in the C++ language is fine (more or
    > less), just exception specifications are 'broken' and 'unusable'. The
    > same article is usually quoted as reference.
    > It's true that C++ exception specifications are not standardized in
    > the most practical way (they are not even standardized as Stroustrup
    > describes them in his book). But they are not more 'broken' than other
    > C++ language elements like templates or the look-up rules.
    > Exception specifications make sense for at least 2 use cases:
    > 1. you guarantee that no exception is thrown form a (usually low
    > level) function. This eg. is important to implement assignment
    > operators.
    > 2. you guarantee that the specified and only the specified
    > exception(s) is(are) thrown from a function. Since exception
    > specifications are part of the contract between the user and you, the
    > implementer, all high level library interfaces should explicitly
    > specify exceptions in code.


    You also guarantee that your whole aplication will crumble whenever you
    or anything that you call breaks that contract. I really don't see the
    point, beside the moderate documentation value of such specifications.
    But even then, everyone knows that destructors and assignment operators
    are nothrow.

    Yes, crashing early is better, yes, I know about all the pretty stuff
    like "contracts" that looks very good on whiteboards and in
    conferences. But when you get down to pragmatic every-day details a
    contract like this may not even be enforceable in a dynamic run-time
    environment where many things can happen, and bringing the whole
    application down because one of the zillions of components broke its
    contract is not acceptable in many real world situations.

    Regards,
    Bart.
    Bart, Sep 25, 2006
    #16
  17. On 25 Sep 2006 10:59:22 -0700, "Bart" <> wrote:
    >You also guarantee that your whole aplication will crumble whenever you
    >or anything that you call breaks that contract...
    >Yes, crashing early is better, yes, I know about all the pretty stuff
    >like "contracts" that looks very good on whiteboards and in
    >conferences. But when you get down to pragmatic every-day details a
    >contract like this may not even be enforceable in a dynamic run-time
    >environment where many things can happen, and bringing the whole
    >application down because one of the zillions of components broke its
    >contract is not acceptable in many real world situations.


    You seem to belief that one cannot programmatically control which
    exception(s) may be thrown from a function (and therefore not use
    except. spec.). Of course, you can. As a library user I want reliable
    information about what a function may throw, eg.

    class Database {
    public:
    void connect (...) throw (DBexcept);
    };

    or maybe even

    class Database {
    public:
    ErrorCode connect (...) throw();
    };


    Best wishes,
    Roland Pibinger
    Roland Pibinger, Sep 25, 2006
    #17
  18. Stuart Golodetz

    Bart Guest

    Roland Pibinger wrote:
    > On 25 Sep 2006 10:59:22 -0700, "Bart" <> wrote:
    > >You also guarantee that your whole aplication will crumble whenever you
    > >or anything that you call breaks that contract...
    > >Yes, crashing early is better, yes, I know about all the pretty stuff
    > >like "contracts" that looks very good on whiteboards and in
    > >conferences. But when you get down to pragmatic every-day details a
    > >contract like this may not even be enforceable in a dynamic run-time
    > >environment where many things can happen, and bringing the whole
    > >application down because one of the zillions of components broke its
    > >contract is not acceptable in many real world situations.

    >
    > You seem to belief that one cannot programmatically control which
    > exception(s) may be thrown from a function (and therefore not use
    > except. spec.). Of course, you can. As a library user I want reliable
    > information about what a function may throw, eg.
    >
    > class Database {
    > public:
    > void connect (...) throw (DBexcept);
    > };


    So what do you do when your network connection fails? Or when a simple
    memory allocation fails? Do you catch every possible exception and then
    re-throw the corresponding DBexcept equivalent? What practical value is
    added by this approach as opposed to just letting everything that you
    don't care about go through?

    Besides, trivial examples are great for classrooms and CTO meatings but
    in general they are of fairly limited applicability. What do you do
    when a third party plug-in doesn't respect its contract? Do you just
    die because you didn't expect it?

    Regards,
    Bart.
    Bart, Sep 25, 2006
    #18
  19. Stuart Golodetz

    Bart Guest

    Bart wrote:
    > Roland Pibinger wrote:
    > > On 25 Sep 2006 10:59:22 -0700, "Bart" <> wrote:
    > > >You also guarantee that your whole aplication will crumble whenever you
    > > >or anything that you call breaks that contract...
    > > >Yes, crashing early is better, yes, I know about all the pretty stuff
    > > >like "contracts" that looks very good on whiteboards and in
    > > >conferences. But when you get down to pragmatic every-day details a
    > > >contract like this may not even be enforceable in a dynamic run-time
    > > >environment where many things can happen, and bringing the whole
    > > >application down because one of the zillions of components broke its
    > > >contract is not acceptable in many real world situations.

    > >
    > > You seem to belief that one cannot programmatically control which
    > > exception(s) may be thrown from a function (and therefore not use
    > > except. spec.). Of course, you can. As a library user I want reliable
    > > information about what a function may throw, eg.
    > >
    > > class Database {
    > > public:
    > > void connect (...) throw (DBexcept);
    > > };

    >
    > So what do you do when your network connection fails? Or when a simple
    > memory allocation fails? Do you catch every possible exception and then
    > re-throw the corresponding DBexcept equivalent? What practical value is
    > added by this approach as opposed to just letting everything that you
    > don't care about go through?
    >
    > Besides, trivial examples are great for classrooms and CTO meatings but


    Typo there. Should be 'meetings'.

    Regards,
    Bart.
    Bart, Sep 25, 2006
    #19
  20. Stuart Golodetz

    Gavin Deane Guest

    Bart wrote:
    > Besides, trivial examples are great for classrooms and CTO meatings but
    > in general they are of fairly limited applicability. What do you do
    > when a third party plug-in doesn't respect its contract? Do you just
    > die because you didn't expect it?


    The first thing you should do is consider an alternative supplier. As
    long as the concept of a third party plug-in (or any other API) failing
    to respect its contract [*] is considered by users of plug-ins to be in
    any way expected or acceptable, software engineering will remain the
    woefully immature discipline it currently is.

    Gavin Deane
    Gavin Deane, Sep 25, 2006
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Philipp Holzschneider
    Replies:
    6
    Views:
    470
    Ron Natalie
    Oct 2, 2003
  2. Scott Brady Drummonds

    Exception Specifications Using Undefined Class

    Scott Brady Drummonds, Jul 29, 2004, in forum: C++
    Replies:
    1
    Views:
    354
    Denis Remezov
    Jul 29, 2004
  3. Replies:
    4
    Views:
    289
    Richard Herring
    Oct 6, 2005
  4. Ioannis Vranos
    Replies:
    22
    Views:
    759
    Ioannis Vranos
    Jan 22, 2008
  5. Keith Halligan

    Exception Specifications

    Keith Halligan, May 2, 2008, in forum: C++
    Replies:
    7
    Views:
    520
    James Kanze
    May 6, 2008
Loading...

Share This Page