Friday, August 23, 2013

FeedaMail: Comments for Sutter̢۪s Mill

feedamail.com Comments for Sutter's Mill

Comment on GotW #7b: Minimizing Compile-Time Dependencies, Part 2 by Alf P. Steinbach

Oh well. Hm. @Thibaud reminded me to add an operator=, which I did (the only answer so far to do that crucial thing), but I did that with an incomplete implementation of swap_with: the A and B base class sub-objects were not swapped in that code. I intended to, but I forgot. I think I forgot it mainly because I do such things by testing the code, and with just empty dummy A and B classes the code worked nicely…

So, here’s an implementation using std::swap, assuming that A and B are no-throw swappable:

  void X::swap_with( X& other )  {      swap<A>( *this, *this );      swap<B>( *this, *this );      swap( p_impl_, other.p_impl_ );  }  

If the no-throw swappable assumption does not hold, then a noexcept would give the compiler incorrect information, so I have removed it here.

In the case where swapping throws one can end up with an inconsistent state, which is the same general effect as with the compiler-generated assignment for the original class X. In more detail, the compiler generated assignment can yield an inconsistent state when copy assignment of a sub-object throws, and the above can yield an inconsistent state when swapping throws, which is most likely due to assignment to that sub-object throwing. Anyway, depending on the properties of the classes one can get an inconsistency.

Summing up so far, to implement a class X copy assignment operator, as opposed to letting the compiler generate one, one has to assume that

• classes A, B, C and D are copy-constructible, and

• the base classes A and Bare swappable (possibly just by providing copy assignment, possibly by specializing std::swap), but not necessarily non-throwing swappable.

If instead of a user-defined X copy assignment operator one uses a cloning smart-pointer for p_impl_, then it’s not strictly necessary to know anything about A.and B. For then the compiler does the job of considering the properties of A.and B when it attempts to generate X copy constructor and copy assignment operator, However, in the case where not all the classes are copy-constructible there is not much point in the cloning smart pointer (it will never be doing its thing), so the code will in practice depend on the properties of the classes.

Read More »

Comment on GotW #7a Solution: Minimizing Compile-Time Dependencies, Part 1 by JonKalb

Excellent comment Sebastian.

Read More »

Comment on GotW #7b: Minimizing Compile-Time Dependencies, Part 2 by Alf P. Steinbach

void X::swap_with( X& other )
{
swap( *this, other );
swap( *this, other );
swap( p_impl_, other.p_impl_ );
}

And having corrected that it now occurred to me,

what if A and B have a common virtual base class?

In that case, since the above code swaps the virtual base sub-object an even number of times, an extra swap of it needs to be added to bring the total number of swaps of this sub-object to an odd number:

void X::swap_with( X& other )
{
swap
( *this, other );
swap( *this, other );
swap( *this, other );
swap( p_impl_, other.p_impl_ );
}

But if that swap is done via copy assignments and is costly, then this is needlessly inefficient.

For, instead – and I didn’t think of this earlier – to cater for the possibility of a common virtual base class for A and B, the X assignment operator can be expressed in terms of assignment, like this:

auto X::operator=( X const& other )
-> X

I don’t think I’d do that optimization, but then, I don’t think I’d use PIMPL to get rid of an #include in the first place.

Read More »

Comment on GotW #7a Solution: Minimizing Compile-Time Dependencies, Part 1 by daramarak

Sebastians comment is truly excellent, Sutter should definitely consider incorporating these explanations into the solution.

Read More »
 
Delievered to you by Feedamail.
Unsubscribe