speed of mpz_odd_p and lazy allocation
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.
More information about the gmp-devel