Topic: Article on exceptions in January C++ Report


Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/03/03
Raw View
Roger Glover wrote:
>
> Is there a true "swapping" situation in which a bitwise swap of values
> does not suffice?  I cannot imagine such a situation!

One simple case:

    struct char_aligner {
        char * align_char;
        char text[81];
        char_aligner(char const t[], char d) {
            memcpy(text, t, sizeof text);
            align_char = strchr(text, d);
            if (!align_char) align_char + text + sizeof text;
        }
        char_aligner(char_aligner const & x) {
            memcpy(text, x.text, sizeof text);
            align_char = text + x.align_char - x.text;
        }
        char_aligner & operator=(char_aligner const & x) {
            memcpy(text, x.text, sizeof text);
            align_char = text + x.align_char - x.text;
            return *this;
        }
    };

If one member points (or refers) to another in the class, a bitwise swap
almost certainly will do the wrong thing.
--
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: hnsngr@sirius.com (Ron Hunsinger)
Date: 1998/03/03
Raw View
In article <6dfc7l$3hl@netlab.cs.rpi.edu>, rmacombe@aruba.u.arizona.edu
(Robert J Macomber) wrote:

> In article <6depnb$l9t@netlab.cs.rpi.edu>,
> Roger Glover  <roger.glover@mindspring.com> wrote:
> >Is there a true "swapping" situation in which a bitwise swap of values
> >does not suffice?  I cannot imagine such a situation!
>
> Yes: if an object contains a pointer to one of its own data members, it
> will break if it's swapped under this scheme.  (I do this frequently
> when an object can contain an arbitrary amount of information, but that
> info is *usually* small in size -- the pointer-to-data points to a
> small buffer which is part of the object itself.)

The compiler will also often do this for classes that have virtual bases.
The derived instance will have a pointer to the virtual base instance,
which occurs (once) within the memory allocated for the most derived
object.

-Ron Hunsinger

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jbuck@Synopsys.COM (Joe Buck)
Date: 1998/03/03
Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote in article
>> >  * swap() has no effects if it throws an exception,

>> I think we pretty much proved, in this newsgroup a few months ago,
that
>> it is impossible to make swap safe for objects whose constructors
might
>> throw.

But swap, if specialized, need not call any constructors.

"greg" <dont@spam.me> writes:
>Sorry, I should have said swapping any of the standard containers will
>not throw an exception.

Also, in most cases where the constructor for T might throw it is
possible
to write a specialization of swap(T&,T&) that does not throw, since it
is almost always possible to do a swap without doing memory allocation
or deallocation, or resource acquisition or freeing.  As Greg suggests,
this needs to be done for the standard containers; it's also a good idea
to do for other objects where a specialized swap is much faster than
the default, which typically does a copy constructor call, two
assignment
operator calls, and a destructor call.
--
-- Joe Buck
"One good rule for avoiding brain death in the mediascape is to question
everything that is not being questioned." -- Jon Carroll

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Martijn Lievaart" <nospam@somewhere.org>
Date: 1998/03/03
Raw View
Roger Glover wrote in message <6depnb$l9t@netlab.cs.rpi.edu>...
--8<--
>If a bitwise swap suffices, there is a way to swap without creating a
>temporary or staging in registers, using only repeated application of
>the
>exclusive or operator:
>
>    a ^= b;
>    b ^= a;  // b now contains the original contents of a
>    a ^= b;  // a now contains the original contents of b
>
--8<--
>
>Is there a true "swapping" situation in which a bitwise swap of values
>does not suffice?  I cannot imagine such a situation!
>

Yes there is.
First you have to realize that a and b *must* be references, not local
values, as the original problem inhibits making copies.
Now when both a and b refer to the same location, the algorith breaks.
While I admit this is not likely, it is possible, so it probably will
happen. This can lead to very obscure bugs.



      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jkanze@otelo.ibmmail.com
Date: 1998/03/03
Raw View
In article <6depnb$l9t@netlab.cs.rpi.edu>,
  roger.glover@mindspring.com wrote:
>
> Paul D. DeRocco wrote:
>
> > greg wrote:
> > >
> > >  * swap() has no effects if it throws an exception,
> >
> > I think we pretty much proved, in this newsgroup a few months ago,
> that it is
> > impossible to make swap safe for objects whose constructors might
> throw. In
> > order to swap a with b, you have to copy a to temporary c, then b to
> a, then c
> > to b;
>
> This would only be so if memberwise copy is required to implement the
> swap.
> If a bitwise swap suffices, there is a way to swap without creating a
> temporary or staging in registers, using only repeated application of
> the
> exclusive or operator:
>
>     a ^= b;
>     b ^= a;  // b now contains the original contents of a
>     a ^= b;  // a now contains the original contents of b
>
> (That didn't do it for you?  Then imagine the objects a and b reinter-
> preted as an arrays of (sizeof(a)) unsigned chars, and a loop with the
> three statements above and some appropriate indexing.)

Not again.

The above fails to work correctly if a and b are the same object.
Swapping the same object does occasionally occur.

> Is there a true "swapping" situation in which a bitwise swap of values
> does not suffice?

Sure.  Anytime an object registers itself somewhere, or contains or uses
pointers to itself.  (A number of implementations of virtual base
classes
use pointers to the object internally, so in practice, anytime there are
virtual base classes, there are a significant number of implementations
where a bitwise swap will cause problems.)

>  I cannot imagine such a situation!

Not much imagination.  In fact, I would almost say, not much experience,
since such cases occur regularly in applications.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung


-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/03/04
Raw View
Robert J Macomber wrote:
>
> Roger Glover  <roger.glover@mindspring.com> wrote:
> >Is there a true "swapping" situation in which a bitwise swap of
> > values
> >does not suffice?  I cannot imagine such a situation!
>
> Yes: if an object contains a pointer to one of its own data members,
> it
> will break if it's swapped under this scheme.

Another common practice is for an object to contain a pointer to a child
object which contains a back-link back to the parent.

--

Ciao,
Paul

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/03/01
Raw View
greg wrote:
>
>  * swap() has no effects if it throws an exception,

I think we pretty much proved, in this newsgroup a few months ago, that it is
impossible to make swap safe for objects whose constructors might throw. In
order to swap a with b, you have to copy a to temporary c, then b to a, then c
to b; if the last one throws, you cannot expect to be able to move a back into
b and put c back into a, so your stuck.

I came up with an elaborate scheme that involved having two objects apparently
at the same address, by memcpy-ing one out, and then constructing a new one in
its place with placement new, but even that fails if you're registering all
created objects in a database indexed by their address.

--

Ciao,
Paul

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "greg" <dont@spam.me>
Date: 1998/03/02
Raw View
Paul D. DeRocco <pderocco@ix.netcom.com> wrote in article
<6d78m5$s4u@netlab.cs.rpi.edu>...
> greg wrote:
> >
> >  * swap() has no effects if it throws an exception,
>
> I think we pretty much proved, in this newsgroup a few months ago, that
> it is impossible to make swap safe for objects whose constructors might
> throw.
..

Sorry, I should have said swapping any of the standard containers will
not throw an exception.

Greg

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Dave Abrahams <abrahams@motu.com>
Date: 1998/03/02
Raw View
Paul D. DeRocco wrote:

> greg wrote:
> >
> >  * swap() has no effects if it throws an exception,
>
> I think we pretty much proved, in this newsgroup a few months ago, that
> it is impossible to make swap safe for objects whose constructors might
> throw. In order to swap a with b, you have to copy a to temporary c,
> then b to a, then c to b; if the last one throws, you cannot expect to
> be able to move a back into b and put c back into a, so your stuck.

I'm not sure exactly what point you're trying to make, but ... the
decision in London referred to in Greg's post was regarding swap() used
on the standard containers. You can specialize swap so that it doesn't
have to use the objects' constructor. If you take a look at the
implementation of swap(vector<T>&, vector<T>&) in the SGI STL (just for
an example), you'll see a counterexample to any "proof" that swap can't
be safe for objects with throwing constructors.

  {Dave's quite right. See also the article in the Nov/Dev 1997 C++
Report. -hps}

-Dave


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Roger Glover <roger.glover@mindspring.com>
Date: 1998/03/02
Raw View
Paul D. DeRocco wrote:

> greg wrote:
> >
> >  * swap() has no effects if it throws an exception,
>
> I think we pretty much proved, in this newsgroup a few months ago,
that it is
> impossible to make swap safe for objects whose constructors might
throw. In
> order to swap a with b, you have to copy a to temporary c, then b to
a, then c
> to b;

This would only be so if memberwise copy is required to implement the
swap.
If a bitwise swap suffices, there is a way to swap without creating a
temporary or staging in registers, using only repeated application of
the
exclusive or operator:

    a ^= b;
    b ^= a;  // b now contains the original contents of a
    a ^= b;  // a now contains the original contents of b

(That didn't do it for you?  Then imagine the objects a and b reinter-
preted as an arrays of (sizeof(a)) unsigned chars, and a loop with the
three statements above and some appropriate indexing.)

Is there a true "swapping" situation in which a bitwise swap of values
does not suffice?  I cannot imagine such a situation!

> if the last one throws, you cannot expect to be able to move a back
into
> b and put c back into a, so your stuck.
>
> I came up with an elaborate scheme that involved having two objects
apparently
> at the same address, by memcpy-ing one out, and then constructing a
new one in
> its place with placement new, but even that fails if you're
registering all
> created objects in a database indexed by their address.

This would also not be a problem with an xor-based bitwise swap, since
it does not require allocation of new storage.


-- Roger Glover


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: rmacombe@aruba.u.arizona.edu (Robert J Macomber)
Date: 1998/03/03
Raw View
In article <6depnb$l9t@netlab.cs.rpi.edu>,
Roger Glover  <roger.glover@mindspring.com> wrote:
>Is there a true "swapping" situation in which a bitwise swap of values
>does not suffice?  I cannot imagine such a situation!

Yes: if an object contains a pointer to one of its own data members, it
will break if it's swapped under this scheme.  (I do this frequently
when an object can contain an arbitrary amount of information, but that
info is *usually* small in size -- the pointer-to-data points to a
small buffer which is part of the object itself.)

--
   Rob Macomber
    (rmacombe@u.arizona.edu)

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Tom Lane <tgl@netcom.com>
Date: 1998/03/03
Raw View
Roger Glover <roger.glover@mindspring.com> writes:
> Paul D. DeRocco wrote:
>> I think we pretty much proved, in this newsgroup a few months ago,
>> that it is impossible to make swap safe for objects whose
>> constructors might throw.

> If a bitwise swap suffices, there is a way to swap without creating a
> temporary or staging in registers, using only repeated application of
> the exclusive or operator:
>     a ^= b;
>     b ^= a;  // b now contains the original contents of a
>     a ^= b;  // a now contains the original contents of b

If you are prepared to assume that swapping the bits suffices, then
none of the interesting issues come up.  The good 'ol triple-xor
trick is useful for doing the swap without much spare storage, but
it has no semantic advantages.

> Is there a true "swapping" situation in which a bitwise swap of values
> does not suffice?  I cannot imagine such a situation!

A reasonably trivial example is a class that holds a pointer to an owned
subobject that itself contains a pointer back to the owner.  A variant
is a class in which some field contains a pointer to the whole object or
a member object.  (Plausible cases can be constructed using pairs of
member objects that need references to each other.)

In these cases, swapping the bits creates semantically incorrect
structures, eg containers whose contained objects point to the
wrong place.

You can perhaps argue that these structures are poor programming
style, but they are counterexamples for any simplistic swap.

   regards, tom lane

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Tom McKearney" <no@spam.com>
Date: 1998/02/23
Raw View
Matt Austern wrote in message <6cjhbk$ru6@netlab.cs.rpi.edu>...

>First, it is no longer true that the C++ standard says nothing about
>exception safety and the standard library.  The standard containers
>and algorithms are explicitly guaranteed to be exception safe.  (Using
>the terminology of my article, all STL algorithms and containers have
>Level 3 exception safety provided that their template arguments
>satisfy the appropriate restrictions, some have Level 4 exception
>safety, and some are guaranteed not to throw exceptions at all.)

Pardon my ignorance, but can someone please instruct me on the
definitions
of various levels of exception safety?

Thanks in advance,

Tom McKearney



      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "greg" <dont@spam.me>
Date: 1998/02/24
Raw View

Tom McKearney <no@spam.com> wrote in article
<6cre6n$qbd@netlab.cs.rpi.edu>...
> Matt Austern wrote in message <6cjhbk$ru6@netlab.cs.rpi.edu>...
> <snip>...
> Pardon my ignorance, but can someone please instruct me on the
> definitions
> of various levels of exception safety?

Following is the summary that Dave Abrahams and I presented at the last
committee meeting. Hope it helps. In our proposals we did not define any
levels per se, but simply made sure that the draft specified for every
library function the conditions, if any, under which it could throw and
the effects, if any, of an exception thrown through the function.

So what rules should the user of the library function follow for types
passed to the library?  A slightly simplified summary is:
 * your destructors must never, ever throw;
 * if your copy constructors and comparison functors never throw then
   then all the containers are safe, that is they won't throw unless
   a type passed into them does (including the allocator), and their
   contents will be unchanged after the throw;
 * if your copy constructors can throw, then stick with lists, maps,
   sets, and stacks, and don't do multiple-element inserts except on
   lists.

Greg Colvin

------------------------------------------------------------------------
In London we made some changes to the library to provide one exception
safe container (list) and one exception safe function (swap).  This
paper identifies the few changes remaining to provide the full degree of
exception safety proposed in J16/97-0048R1 = WG21/N1086R1. We remain
convinced that without these changes the library does not yet specify
sufficient exception safety.

One sticking point in London was the lack of a clear and simple
statement of just what degree of safety the library should provide.  A
slightly over-simplified statement of the post-London status quo is:
 * swap() is safe;
 * list is safe.

To be more precise:
 * swap() has no effects if it throws an exception,
 * erasing elements off a list will not throw, and
 * inserting elements on a list has no effects if it does throw.

To be even more precise:
 * swap() is safe on an associative container only if its Compare
   object can be copied without throwing.

We propose to enlarge that statement to:
 * swap is safe;
 * list, map, set, multimap, and multiset are safe;
 * vector and deque are safe if they contain PODs;
 * stack and queue are safe;
 * iterators returned from standard containers are safe.

To be more precise:
 * multiple-element insertions are safe only for list;
 * an insert() or erase() on a vector or deque is safe only if it
   contains a type which can be copied without throwing;
 * pop_back() and pop_front() will not throw;
 * push_back() and push_front() have no effects if they do throw; and
 * an iterator returned from a standard container can be copied without
   throwing.

The associative containers can be made safe almost easily as can list,
and for the same reason: they are node-based, so any failure to
construct a node simply leaves the container as it was, and given that
destructors don't throw there is no reason for removing a node to fail.
However, for multiple-element operations the need to keep elements
sorted makes full recovery from a throw impractical.

Vector and deque are array-based containers, and so cannot fully recover
when a contained type's copy operation throws, because of the need to
copy elements when resizing or inserting. Objects like PODs, whose copy
operations do not throw, are common enough that the more limited
guarantee is still useful.  However, push and pop operations do not
require copying existing elements, and so are safe even if copying
throws, as are the adaptors that use those operations.

The iterators returned from standard containers need to be copyable
without throwing so that it is possible to roll back insertions by
calling erase().


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Matt Austern <austern@isolde.mti.sgi.com>
Date: 1998/02/20
Raw View
I wrote an article about exceptions and the standard C++ library
("Making the World Safe for Exceptions") that was published in the
January 1998 issue of C++ Report.  Unfortunately, when I actually read
that issue a couple of weeks ago, I noticed that something very
important had failed to get printed: an author's note that I intended
to go at the end of the article.  Someone---maybe an editor, maybe
me---goofed.

The problem is that I originally wrote that article almost a year ago,
and some of the things I said in it are no longer true.  My intention
was to note, briefly, some of the things that had changed.

First, it is no longer true that the C++ standard says nothing about
exception safety and the standard library.  The standard containers
and algorithms are explicitly guaranteed to be exception safe.  (Using
the terminology of my article, all STL algorithms and containers have
Level 3 exception safety provided that their template arguments
satisfy the appropriate restrictions, some have Level 4 exception
safety, and some are guaranteed not to throw exceptions at all.)

Second, there are now some new techniques for exception safety of
generic conatiners in addition to the ones that I discussed in that
article.  In some cases the new techniques (I'm thinking in particular
of the base class initialization technique) are cleaner and more
efficient than the equivalent ones from my article.

Third and most important, Dave Abrahams is responsible for many of
these changes.  He did a lot of work on exception safety of generic
containers, and he managed to convince the C++ standardization
committee that guarantees of exception safety were important and
practical.

I'm sorry that this note didn't get printed along with my article.

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]