By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,117 Members | 1,093 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,117 IT Pros & Developers. It's quick & easy.

why a member "swap" function shouldn't throw?

P: n/a
Hello,

It is said that if I implement a "swap" member function, then it
should never throw any exception. However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?

Thanks,
Jess

Jun 15 '07 #1
Share this Question
Share on Google+
28 Replies


P: n/a
Jess <wd***@hotmail.comwrote:
It is said that if I implement a "swap" member function, then it
should never throw any exception. However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?
I think the restriction should apply with non-member functions as well.
Jun 15 '07 #2

P: n/a
On 15 Jun, 13:21, Jess <w...@hotmail.comwrote:
Hello,

It is said that if I implement a "swap" member function, then it
should never throw any exception. However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?
I think that the restriction must apply regardless to whether it is
member or not.

consider

struct A
{
T1 t1_;
T2 t2_;
};

void swap(A & l, A & r)
{
swap(l.t1, r.t1);
swap(l.t2, r.t2);
}

and second swap throws, then you have
half swapped objects.

regards

DS

Jun 15 '07 #3

P: n/a
dasjotre wrote:
void swap(A & l, A & r)
{
swap(l.t1, r.t1);
swap(l.t2, r.t2);
}

and second swap throws, then you have
half swapped objects.
But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
Jun 15 '07 #4

P: n/a
ppi
On Jun 15, 10:37 am, dasjotre <dasjo...@googlemail.comwrote:
On 15 Jun, 13:21, Jess <w...@hotmail.comwrote:
Hello,
It is said that if I implement a "swap" member function, then it
should never throw any exception. However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?

I think that the restriction must apply regardless to whether it is
member or not.

consider

struct A
{
T1 t1_;
T2 t2_;

};

void swap(A & l, A & r)
{
swap(l.t1, r.t1);
swap(l.t2, r.t2);

}

and second swap throws, then you have
half swapped objects.

regards

DS
swap members should not throw, since most of the times these are the
method used to build a correct operator=(). If swap throws it's
impossible to get operator=() to work properly.
I think H.Sutter wrote about it in one of its books (dunno if you can
find someting in gotw though):

T& operator=( const T& src )
{
T temp(src); // can throw
this->swap( temp );// PLZ do not throw !
return *this;// will not throw
}

If swap throws, we end-up with an ill-formed object, its members state
is unknown.
if the construction of the temp throws it's ok, operator= failed, but
the object is in a clean state - nothing happened.

swap defined outside classes have other purposes, they can carry
business logic with them, they are allowed to throw most of the time.

They do have have the same name, but their purpose are slightly
different.
Hope this will help.

Cheers,
paulo

Jun 15 '07 #5

P: n/a
On Jun 15, 10:44 am, Eberhard Schefold
[snip]
But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
I think it should probably be "commit or roll back"
not "no throws." That is to say, the code should
be constructed such that it can't leave the data
in an unpredictable state. It should either work
correctly or leave the data in the state it was.

For tiny objects being swapped you can be fairly
confident that you won't get an error. Except maybe
a stack problem if you happened to be *right* at the
edge and put one more automatic on there.

But I'm not sure you *can* promise no throws when
you are talking about larger objects being swapped.
Consider, just as an example, you may be required
to do an assign of one object to another to do the
swap. And that might call new, and that might get
you to the end of the freestore. Or fail on some
other resource.
Socks

Jun 15 '07 #6

P: n/a
On 15 Jun, 15:44, Eberhard Schefold <eberhard.schef...@de.bosch.com>
wrote:
dasjotre wrote:
void swap(A & l, A & r)
{
swap(l.t1, r.t1);
swap(l.t2, r.t2);
}
and second swap throws, then you have
half swapped objects.

But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
if you mean try {}catch(...){ do nothing } I agree completely.
it is 'no solution'

you could use PIMPL, swap then becomes
just a swap of pointers and I can not think
of a case when that failed ;)

regards

DS

Jun 15 '07 #7

P: n/a
On 15 Jun, 15:48, ppi <vod...@gmail.comwrote:
I think H.Sutter wrote about it in one of its books (dunno if you can
find someting in gotw though):
indeed
http://www.gotw.ca/gotw/059.htm

regards

DS

Jun 15 '07 #8

P: n/a
On Fri, 15 Jun 2007 05:21:10 -0700, Jess wrote:
>It is said that if I implement a "swap" member function, then it
should never throw any exception.
This may be a recommendation but it's not a fixed requirement. You can
use the exception specification throw() to guarantee that no exception
is thrown from a function.
>However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?
You probably mean a specialization for std::swap() here. AFAIK, there
are no restrictions WRT exceptions for std::swap().
--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
Jun 15 '07 #9

P: n/a
Eberhard Schefold <eb***************@de.bosch.comwrote:
dasjotre wrote:
void swap(A & l, A & r)
{
swap(l.t1, r.t1);
swap(l.t2, r.t2);
}

and second swap throws, then you have
half swapped objects.

But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
There is no reason for a swap to fail (other than truly incredible
circumstances that can't be detected before hand in any case.)
Jun 15 '07 #10

P: n/a
Puppet_Sock <pu*********@hotmail.comwrote:
On Jun 15, 10:44 am, Eberhard Schefold
But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?

I think it should probably be "commit or roll back" not "no throws."
That is to say, the code should be constructed such that it can't
leave the data in an unpredictable state. It should either work
correctly or leave the data in the state it was.

For tiny objects being swapped you can be fairly confident that you
won't get an error. Except maybe a stack problem if you happened to
be *right* at the edge and put one more automatic on there.

But I'm not sure you *can* promise no throws when you are talking
about larger objects being swapped.
Larger objects are just collections of tiny objects. There is no
reason for a large object swap to fail either.
Consider, just as an example, you may be required to do an assign of
one object to another to do the swap.
Maybe an example would help?
Jun 15 '07 #11

P: n/a
rp*****@yahoo.com (Roland Pibinger) wrote in news:4672bdfb.9209182
@news.utanet.at:
On Fri, 15 Jun 2007 05:21:10 -0700, Jess wrote:
>>It is said that if I implement a "swap" member function, then it
should never throw any exception.

This may be a recommendation but it's not a fixed requirement. You can
use the exception specification throw() to guarantee that no exception
is thrown from a function.
Um. No. throw() says that you don't intend for exceptions to be
thrown/escape from that function... but in reality, should an exception end
up attempting to escape from that function, all that will do it convert
that exception into a std::bad_exception. So specifying throw() doesn't
guarantee that there will be no exceptions in that function.

Jun 15 '07 #12

P: n/a
Andre Kostur wrote:
rp*****@yahoo.com (Roland Pibinger) wrote in news:4672bdfb.9209182
@news.utanet.at:
>On Fri, 15 Jun 2007 05:21:10 -0700, Jess wrote:
>>It is said that if I implement a "swap" member function, then it
should never throw any exception.
This may be a recommendation but it's not a fixed requirement. You can
use the exception specification throw() to guarantee that no exception
is thrown from a function.

Um. No. throw() says that you don't intend for exceptions to be
thrown/escape from that function... but in reality, should an exception end
up attempting to escape from that function, all that will do it convert
that exception into a std::bad_exception. So specifying throw() doesn't
guarantee that there will be no exceptions in that function.
You won't ever get any exception whose type is not listed in the throw
specifier.

If an exception is thrown that doesn't match the throw specifier, the
implementation calls unexpected(). The default behavior of unexpected()
is to call terminate().

Your application can replace the unexpected handler by calling
set_unexpected with the address of a suitable handler function. The
handler function isn't allowed to return. It can call terminate(), it
can throw another exception object, or it can rethrow the object that
was thrown. If it throws an exception whose type is one of the types
listed in the throw specifier, then unwinding continues. If it throws an
exception whose type is not listed in the throw specifier AND the list
of types in the throw specifier includes std::bad_exception, the thrown
exception object is replaced by an object of type std::bad_exception. If
the list of types in the throw specifier does not include
std::bad_exception, the implementation calls terminate().

The details are in [except.unexpected]. They're summarized in the third
paragraph of that section:

Thus, an exception-specification guarantees that only
the listed exceptions will be thrown. If the
exception-specification includes the type std::bad_exception
then any exception not on the list may be replaced by
std::bad_exception within the function std::unexpected().

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Jun 15 '07 #13

P: n/a
On Jun 15, 12:39 pm, "Daniel T." <danie...@earthlink.netwrote:
Puppet_Sock <puppet_s...@hotmail.comwrote:
On Jun 15, 10:44 am, Eberhard Schefold
But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
I think it should probably be "commit or roll back" not "no throws."
That is to say, the code should be constructed such that it can't
leave the data in an unpredictable state. It should either work
correctly or leave the data in the state it was.
For tiny objects being swapped you can be fairly confident that you
won't get an error. Except maybe a stack problem if you happened to
be *right* at the edge and put one more automatic on there.
But I'm not sure you *can* promise no throws when you are talking
about larger objects being swapped.

Larger objects are just collections of tiny objects. There is no
reason for a large object swap to fail either.
Um. I'm not altogether sure I agree with the intent of that.
An object with a file handle isn't *just* a collection of
smaller objects. An object with a pointer to memory that
the object allocated isn't *just* a collection of smaller
objects. Both of these are also "managers" of other data.
That data may or may not get copied if the object is copied,
may (probably) or may not get swapped if the objects are.
Consider, just as an example, you may be required to do an assign of
one object to another to do the swap.

Maybe an example would help?
Consider a swap based on the tired old temp object.

// fill in the function header stuff as usual
myClass tmp; // 1
tmp = a; // 2
a = b; // 3
b = tmp; // 4

The "function header stuff" could, in principle,
blow the stack. Don't know if a try-catch can
solve that little problem, but let's move on.

Line 1 could involve calls to new, and so could fail.
It's not likely to fail for built in things like ints.
Though it could blow the stack if you were right at
the edge. I seem to recall saying that. Again, I don't
know what a try-catch would do for you in that case.

But if myClass's default ctor involves a call to new,
it could easily blow the freestore. Or, if some other
resource is involved, that could throw. Say it needs a
temp file or something. Maybe the system runs out of
file handles, or the disk is full, or the network times
out or some silly thing.

Line 2 might also involve calls to new, or allocating
resources. Maybe myClass's default ctor just allocates
some stub or something, then the copy does a deep
copy. So now, tmp has to have a copy of all of a's
resources. That might blow the freestore.

Line 3, same thing, particularly if b is lots bigger
than a. And line 4, again, same thing, particularly if
a is lots bigger than b.

I don't think it's possible to do these operations in
such a way that it's not possible for a throw. It is
possible to do them, with some effort, such that there
won't be an unpredictable data state. Either the swap
will work, or an exception gets thrown and the data
goes back to where it was before the operation started.
Socks

Jun 15 '07 #14

P: n/a
Puppet_Sock <pu*********@hotmail.comwrote:
Larger objects are just collections of tiny objects. There is no
reason for a large object swap to fail either.

Um. I'm not altogether sure I agree with the intent of that.
An object with a file handle isn't *just* a collection of
smaller objects.
Well no, in that case it is a simple pointer, swapping them is a
no-brainer.
An object with a pointer to memory that
the object allocated isn't *just* a collection of smaller
objects.
Again, you are simply swapping two pointers.
Consider, just as an example, you may be required to do an assign of
one object to another to do the swap.
Maybe an example would help?

Consider a swap based on the tired old temp object.

// fill in the function header stuff as usual
myClass tmp; // 1
tmp = a; // 2
a = b; // 3
b = tmp; // 4

The "function header stuff" could, in principle,
blow the stack. Don't know if a try-catch can
solve that little problem, but let's move on.

Line 1 could involve calls to new, and so could fail.
[...]
Line 2 might also involve calls to new, or allocating
resources.
[...]
Line 3, same thing, particularly if b is lots bigger
than a.
Then provide a swap member-function that doesn't do that. Someone else
has already provided a link to the GotW article that shows that, in
principle, any class can provide an exception safe swap function. This
is old ground.
Jun 15 '07 #15

P: n/a
Pete Becker <pe**@versatilecoding.comwrote in
news:Jr******************************@giganews.com :
Andre Kostur wrote:
>rp*****@yahoo.com (Roland Pibinger) wrote in news:4672bdfb.9209182
@news.utanet.at:
>>On Fri, 15 Jun 2007 05:21:10 -0700, Jess wrote:
It is said that if I implement a "swap" member function, then it
should never throw any exception.
This may be a recommendation but it's not a fixed requirement. You
can use the exception specification throw() to guarantee that no
exception is thrown from a function.

Um. No. throw() says that you don't intend for exceptions to be
thrown/escape from that function... but in reality, should an
exception end up attempting to escape from that function, all that
will do it convert that exception into a std::bad_exception. So
specifying throw() doesn't guarantee that there will be no exceptions
in that function.

You won't ever get any exception whose type is not listed in the throw
specifier.

If an exception is thrown that doesn't match the throw specifier, the
implementation calls unexpected(). The default behavior of
unexpected() is to call terminate().

Your application can replace the unexpected handler by calling
set_unexpected with the address of a suitable handler function. The
handler function isn't allowed to return. It can call terminate(), it
can throw another exception object, or it can rethrow the object that
was thrown. If it throws an exception whose type is one of the types
listed in the throw specifier, then unwinding continues. If it throws
an exception whose type is not listed in the throw specifier AND the
list of types in the throw specifier includes std::bad_exception, the
thrown exception object is replaced by an object of type
std::bad_exception. If the list of types in the throw specifier does
not include std::bad_exception, the implementation calls terminate().

The details are in [except.unexpected]. They're summarized in the
third paragraph of that section:

Thus, an exception-specification guarantees that only
the listed exceptions will be thrown. If the
exception-specification includes the type std::bad_exception
then any exception not on the list may be replaced by
std::bad_exception within the function std::unexpected().

Apparently my memory is bad. I thought it was always translated to
std::bad_exception.
Jun 15 '07 #16

P: n/a
On Jun 15, 2:21 pm, Jess <w...@hotmail.comwrote:
It is said that if I implement a "swap" member function, then it
should never throw any exception. However, if I implement "swap" non-
member function, then the restriction doesn't apply. Can somebody tell
me why?
More convention that anything else. A non-member function can
usually not to much else but to use the conventional algorithm:

T tmp( a ) ;
a = b ;
b = tmp ;

This involves constructing a new object (the tmp), which can
often throw. A member function, however, has access to the
underlying types: pointers, etc., and can usually avoid deep
copy by just swapping the pointers. This is not only
significantly faster in some cases, but swapping two pointers,
even with the above algorithm, will not throw.

Being able to swap without throwing means that we can
effectively copy without throwing: if I have something like:

T x, y ;
x.swap( y ) ;

has the same effect on x as copying y into x, except that a real
copy might throw (since it would deep copy all of y---here that
is avoided by allowing y to become a copy of x, effectively
swapping ownership of any resources, rather than allocating them
new).

This is in turn very useful for things like operator=. Consider
an object that uses the compilation firewall idiom:

// Classical op=
T&
T::operator=( T const& rhs )
{
if ( this != &rhs ) {
delete pImpl ;
pImpl = new Impl( *rhs.pImpl ) ;
// What happens if the above line throws???
}
return *this ;
}

// Using swap.
T&
T::operator=( T const& rhs )
{
T tmp( rhs ) ; // Actual copy, and possible throw,
// occurs here.
std::swap( tmp.pImpl, pImpl ) ;
// Now this is the actual copy, and
// tmp holds all our old resources.
return *this ; // Destructs tmp, thus freeing our
// old resources.
}

Of course, this can be done without swap; I could have just
copied the impl into a temporary pointer, deleted my pImpl, and
then assigned it with the results of the copy. (Which is still
the way I write something as simple as the compilation firewall
idiom.) Doing it this way becomes a bit more complicated,
however, when I have more members, all of which need the same
treatment. And since I'm actually swapping, why not make the
function available at the public interface level? That way, a
class which doesn't use the compilation firewall idiom, but uses
an instance of my class, can easily implement its own no-throw
version of swap. The benefit propagates.

Note, however, that all of this concerning swap is just a means
to an end, and in no way necessary. The important thing isn't
swap; it's having an assignment operator that doesn't leave the
object in an undefined state if copying something in it throws.
Having a no-throw version of swap is just a convenient and
conventional method of ensuring that this is posssible, and in
fact rather easy.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 16 '07 #17

P: n/a
On Jun 15, 4:53 pm, Puppet_Sock <puppet_s...@hotmail.comwrote:
On Jun 15, 10:44 am, Eberhard Schefold
[snip]
But what is the alternative? Suppressing any errors and have an
erroneous state without a chance of knowing?
I think it should probably be "commit or roll back"
not "no throws." That is to say, the code should
be constructed such that it can't leave the data
in an unpredictable state. It should either work
correctly or leave the data in the state it was.
Those last two statements say different things, and the last is
often more than you need. Depending on the application, a
simple guarantee that the object can be destructed may be
enough. But even that's not obvious unless you are careful.
For tiny objects being swapped you can be fairly
confident that you won't get an error. Except maybe
a stack problem if you happened to be *right* at the
edge and put one more automatic on there.
But I'm not sure you *can* promise no throws when
you are talking about larger objects being swapped.
The whole point of having a member function is that it can swap
the resources, rather than reallocating them to make a deep
copy, as a non-member would have to. When I use the swap idiom
in an assignment operator, for example, I use std::swap for the
built in types, and a member function swap for class types. If
any of the types involved is a class without a member function
swap, I presume that it cannot be swapped without exceptions,
and that the classical swap assignment operator cannot be used.
Consider, just as an example, you may be required
to do an assign of one object to another to do the
swap. And that might call new, and that might get
you to the end of the freestore. Or fail on some
other resource.
It's always possible to write a no throw swap if you control all
of the classes involved. A member swap function swaps all of
the elements, using a global swap for non class types (for which
the generic std::swap cannot throw), and a member swap for class
types (which is written in the same vein). Recursively, we
always end up with built-in types (maybe pointers), which can be
swapped without throwing.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 16 '07 #18

P: n/a
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:

[...]
Then provide a swap member-function that doesn't do that. Someone else
has already provided a link to the GotW article that shows that, in
principle, any class can provide an exception safe swap function. This
is old ground.
The statement that "any class can provide an exception safe swap
function" isn't true. The statement should be that any class
which consists of only non-class types or class types which
provide an exception safe swap function can provide an exception
safe swap function. If you control all of the classes involved,
this is not a problem; if you encounter an element of a class
type which doesn't provide an exception safe swap function, you
add it to that class, ad infitum, until you reach non class
types. If you don't have that control, i.e. you are using third
party libraries which you cannot modify, it may not be possible
to provide a no throw swap function. And in the same way that
the possibility can propagate through your code, the
impossibility propagates up.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 16 '07 #19

P: n/a
James Kanze <ja*********@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do that. Someone else
has already provided a link to the GotW article that shows that, in
principle, any class can provide an exception safe swap function. This
is old ground.

The statement that "any class can provide an exception safe swap
function" isn't true.
Any class can, in principle, be written using the pimpl idiom, and a
class using the pimpl idiom can always provide an exception safe swap.
The statement should be that any class
which consists of only non-class types or class types which
provide an exception safe swap function can provide an exception
safe swap function. If you control all of the classes involved,
this is not a problem;
You don't need to control all the classes involved... simply write your
class using a single pointer as a member. That way your class will
consist "of only non-class types".
Jun 16 '07 #20

P: n/a
On Jun 16, 6:07 pm, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do that. Someone else
has already provided a link to the GotW article that shows that, in
principle, any class can provide an exception safe swap function. This
is old ground.
The statement that "any class can provide an exception safe swap
function" isn't true.
Any class can, in principle, be written using the pimpl idiom, and a
class using the pimpl idiom can always provide an exception safe swap.
So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."
The statement should be that any class
which consists of only non-class types or class types which
provide an exception safe swap function can provide an exception
safe swap function. If you control all of the classes involved,
this is not a problem;
You don't need to control all the classes involved... simply write your
class using a single pointer as a member. That way your class will
consist "of only non-class types".
That's often a way of getting around the problem, yes.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 16 '07 #21

P: n/a
James Kanze <ja*********@gmail.comwrote:
On Jun 16, 6:07 pm, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do that. Someone else
has already provided a link to the GotW article that shows that, in
principle, any class can provide an exception safe swap function. This
is old ground.
>
The statement that "any class can provide an exception safe swap
function" isn't true.
Any class can, in principle, be written using the pimpl idiom, and a
class using the pimpl idiom can always provide an exception safe swap.

So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."
Therefore, any class can provide an exception safe swap. What's your
point? My point is, if you are writing a class, and you want to provide
an exception safe swap, then you have no excuses... Just do it.
Jun 17 '07 #22

P: n/a
Daniel T. wrote:
James Kanze <ja*********@gmail.comwrote:
>On Jun 16, 6:07 pm, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do that. Someone
else has already provided a link to the GotW article that shows
that, in principle, any class can provide an exception safe swap
function. This is old ground.

The statement that "any class can provide an exception safe swap
function" isn't true.

Any class can, in principle, be written using the pimpl idiom, and a
class using the pimpl idiom can always provide an exception safe swap.

So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."

Therefore, any class can provide an exception safe swap. What's your
point? My point is, if you are writing a class, and you want to provide
an exception safe swap, then you have no excuses... Just do it.
I doubt the "therefore" part, but maybe, I am missing something. Could you
demonstrate/illustrate your claim by providing an implementation of the
pair-template (known from std::pair) with an added thread safe swap member?

Note that the members first and second in std::pair are not member
functions. I do not see how an implementation based on the pimpl idiom can
conform to that interface (which sometimes, as in the case of std::pair,
may not be for you to change).
Best

Kai-Uwe Bux
Jun 17 '07 #23

P: n/a
Kai-Uwe Bux <jk********@gmx.netwrote:
Daniel T. wrote:
My point is, if you are writing a class, and you want to provide
an exception safe swap, then you have no excuses... Just do it.

I doubt the "therefore" part, but maybe, I am missing something. Could you
demonstrate/illustrate your claim by providing an implementation of the
pair-template (known from std::pair) with an added thread safe swap member?
That is not a class that you are writing. It was created by someone
else.* Again, if you are writing a class, and you want to provide an
exception safe swap, then you have no excuses.

* However, the obvious answer is to provide a non-throw swap function
for both elements in the pair...
Jun 17 '07 #24

P: n/a
Daniel T. wrote:
Kai-Uwe Bux <jk********@gmx.netwrote:
>Daniel T. wrote:
My point is, if you are writing a class, and you want to provide
an exception safe swap, then you have no excuses... Just do it.

I doubt the "therefore" part, but maybe, I am missing something. Could
you demonstrate/illustrate your claim by providing an implementation of
the pair-template (known from std::pair) with an added thread safe swap
member?
What made you snip the sentence that I was explicitly referring to?

Daniel T. wrote:
>>James Kanze <ja*********@gmail.comwrote:
So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."

Therefore, any class can provide an exception safe swap. What's your
point?
Your claim, as I understood it, was that _any class_ can provide an
exception safe swap _because_ one can always use pimpl. I still don't see
how to do that for std::pair<>.

That is not a class that you are writing. It was created by someone
else.*
So what? Are classes specified by others not included in "any class"?

I have been told that some programmers have to program according to specs
given to them. I just think, the hint "use pimpl" is not helpful in some of
those cases.

Again, if you are writing a class, and you want to provide an
exception safe swap, then you have no excuses.
I agree that if you _design_ a class (as opposed to provide an
implementation for an already specified class) you can make sure that a
swap member can be implemented in an exception safe way (provided you have
similar control over all member objects). That, however, is a somewhat
weaker statement than the claim that _any class_ can provide an exception
safe swap member function. It's more like: whenever you face a class for
which you cannot implement swap() in an exception safe way, the fault is
with the design and that class could be replaced (absent other
considerations) by a different class that does not suffer from the flaw.

You are right to make that point. It is an important point that puts the
problem into the context of class design, where it belongs. I just thought
that your pimpl remark might be an overgeneralization.
Best

Kai-Uwe Bux
Jun 17 '07 #25

P: n/a
On Jun 17, 2:20 am, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 16, 6:07 pm, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do
that. Someone else has already provided a link to the
GotW article that shows that, in principle, any class
can provide an exception safe swap function. This is
old ground.
The statement that "any class can provide an exception
safe swap function" isn't true.
Any class can, in principle, be written using the pimpl
idiom, and a class using the pimpl idiom can always
provide an exception safe swap.
So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."
Therefore, any class can provide an exception safe swap.
You seem to have problems understanding English. It might be
possible to rewrite almost all classes so that they can provide
an exception safe swap, but you do have to rewrite the class,
and there can be very pertinent reasons why you can't. A class
which has a data member which doesn't provide an exception safe
swap, or which inherits from a class which doesn't provide an
exception safe swap, cannot normally provide an exception safe
swap.
What's your point? My point is, if you are writing a class,
and you want to provide an exception safe swap, then you have
no excuses... Just do it.
If you can. You can't always. And in many cases, there's no
point in it. (I never provide one for entity classes, for
example, which don't support copy or assignment. Even when I
trivially could---there's just no point in it.)

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 17 '07 #26

P: n/a
Kai-Uwe Bux <jk********@gmx.netwrote:
Daniel T. wrote:
Kai-Uwe Bux <jk********@gmx.netwrote:
Daniel T. wrote:
>
My point is, if you are writing a class, and you want to
provide an exception safe swap, then you have no excuses...
Just do it.
>
I doubt the "therefore" part, but maybe, I am missing something.
Could you demonstrate/illustrate your claim by providing an
implementation of the pair-template (known from std::pair) with
an added thread safe swap member?

What made you snip the sentence that I was explicitly referring to?
You were referring to an ancillary comment rather than addressing the
point I was making. As the part I didn't snips says, "My point is..."
Your claim, as I understood it, was that _any class_ can provide an
exception safe swap _because_ one can always use pimpl. I still
don't see how to do that for std::pair<>.
No, my claim as I have actually stated is, "If you are writing a
class, and you want to provide an exception safe swap, then you can do
that."
Again, if you are writing a class, and you want to provide an
exception safe swap, then you have no excuses.

I agree that if you _design_ a class (as opposed to provide an
implementation for an already specified class) you can make sure
that a swap member can be implemented in an exception safe way
(provided you have similar control over all member objects).
Again, you don't need "similar control over all member objects." If
you are *designing* the class then you *can* provide an exception safe
swap. (period, full-stop.) No "provided", no excuses.
You are right to make that point. It is an important point that puts
the problem into the context of class design, where it belongs. I
just thought that your pimpl remark might be an overgeneralization.
Accepted.
Jun 17 '07 #27

P: n/a
Daniel T. wrote:
Kai-Uwe Bux <jk********@gmx.netwrote:
>I agree that if you _design_ a class (as opposed to provide an
implementation for an already specified class) you can make sure
that a swap member can be implemented in an exception safe way
(provided you have similar control over all member objects).

Again, you don't need "similar control over all member objects." If
you are *designing* the class then you *can* provide an exception safe
swap. (period, full-stop.) No "provided", no excuses.
You still have to deal with tradeoffs in design issues. Suppose you have a
library designed to be used by deriving from its classes (this library has
some very good things going for it: replacing it would incur high
development costs on your part). Also suppose that its classes do not
provide exception safe assignment or swap. In that case, classes derived
from the library classes will have a hard time providing an exception safe
swap and designing your classes so that they have an exception safe swap
member may require you to write a complete wrapper around the library. You
are probably right that it _can_ be done, but you may be wrong in claiming
that there are "no excuses" for not doing it. Oftentimes, it just might not
be cost effective.
Best

Kai-Uwe Bux
Jun 17 '07 #28

P: n/a
In article <11**********************@c77g2000hse.googlegroups .com>,
James Kanze <ja*********@gmail.comwrote:
On Jun 17, 2:20 am, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 16, 6:07 pm, "Daniel T." <danie...@earthlink.netwrote:
James Kanze <james.ka...@gmail.comwrote:
On Jun 15, 9:47 pm, "Daniel T." <danie...@earthlink.netwrote:
Then provide a swap member-function that doesn't do
that. Someone else has already provided a link to the
GotW article that shows that, in principle, any class
can provide an exception safe swap function. This is
old ground.
The statement that "any class can provide an exception
safe swap function" isn't true.
Any class can, in principle, be written using the pimpl
idiom, and a class using the pimpl idiom can always
provide an exception safe swap.
So it's not "any class can provide an exception safe swap
function", but "any class using the pimpl idiom can provide an
exception safe swap function."
Therefore, any class can provide an exception safe swap.

You seem to have problems understanding English. It might be
possible to rewrite almost all classes so that they can provide
an exception safe swap, but you do have to rewrite the class,
and there can be very pertinent reasons why you can't. A class
which has a data member which doesn't provide an exception safe
swap, or which inherits from a class which doesn't provide an
exception safe swap, cannot normally provide an exception safe
swap.
Some may object: "Aha! Therefore this proves exception safety is
unattainable in general, because you can't solve the general problem
of making any arbitrary class strongly exception-safe without
changing the class!"

Such a position is unreasonable and untenable. The Pimpl
transformation, a minor structural change, IS the solution to the
general problem. To say, "no, you can't do that, you have to be able
to make an arbitrary class exception-safe without any changes," is
unreasonable for the same reason that "you have to be able to make an
arbitrary class meet New Requirement #47 without any changes" is
unreasonable.

...You Can Always Make Your Code (Nearly) Strongly Exception-Safe

There's an important principle here:

Just because a class you use isn't in the least exception-safe is no
reason that YOUR code that uses it can't be (nearly) strongly
exception-safe.

Not my words, that's a quote from Herb Sutter...
http://www.gotw.ca/gotw/059.htm
Jun 18 '07 #29

This discussion thread is closed

Replies have been disabled for this discussion.