speed of mpz_odd_p and lazy allocation

Marc Glisse marc.glisse at inria.fr
Sat Aug 18 14:56:47 CEST 2012

On Wed, 15 Aug 2012, Niels Möller wrote:

> Marc Glisse <marc.glisse at inria.fr> writes:
>> Hm, the reads are sometimes too eager, but when a write happens, it is
>> usually important, so writing it to a scratch location is strange.
> You may well be right (I haven't checked the code which does this). If
> so, that seems to kill the idea of pointing to a writable scratch limb.

There is still the readable scratch limb ;-)

>> My main use cases are dictated by C++.
>> It would help if mpz_class::mpz_class() didn't throw => mpz_init
>> doesn't throw.
> Out of curiosity (I'm not really into C++), how would that help? I
> thought it was fairly normal for constructors to allocate memory and
> potentially fail when doing that.

It is. Except possibly for the default and move constructors.

Consider a container (std::vector) from the standard library. One very 
common operation we can do is append an element. Sometimes, that requires 
a new allocation, and copying all the data from the old to the new place. 
And that's how it was implemented: allocate a new region, copy the 
elements, now tell the vector about this new region and destroy the old 
one (and finally you can append). If an exception is thrown at any point, 
the vector remains exactly as it was before we called the insertion 
function, which is a fundamental guarantee.

Now copying data can be slow (think about a large mpz_t). Since the old 
elements are meant to be destroyed anyway, we might as well steal their 
resources to speed things up. That's where move constructors appear. One 
can now define something that is similar to a copy constructor, except 
that it leaves the original object in some arbitrary state, so in 
particular it can steal its resources. Let's follow the implementation. We 
allocate a new region, move the objects... oh! an exception occurs. What 
now? Well, my vector is in some half-moved state, I can't do anything with 
it. Trying to move the objects back to their original position would 
likely just throw again, so I can't do that either. I have lost my vector.

=> The optimized implementation is thus only used when moving is 
guaranteed not to throw.

For the default constructor, I can't find it anymore, but I believe there 
were similar reasons why having it not throw is desirable. In any case, 
from an implementation point of view, both often come from the existence 
of an empty state.

The fact that objects moved from must still be in a valid (if 
unpredictable) state is a much debated question, but yes, they must.

Marc Glisse

More information about the gmp-devel mailing list