这是 C 语言中的不良做法 - 故事结束。您不检查_amount 是否已初始化。 GMP 库经过高度优化,确保正确初始化mpz_t 对象是唯一正确的方法。所以mpz_t 对象可能看起来已初始化,但除非mpz_init(_amount) 已被使用,否则这些字段可能是未初始化的垃圾。
_amount 是否已经设置无关紧要。看mpz/set.c:
void
mpz_set (mpz_ptr w, mpz_srcptr u)
{
mp_ptr wp, up;
mp_size_t usize, size;
usize = SIZ(u);
size = ABS (usize);
wp = MPZ_REALLOC (w, size);
up = PTR(u);
MPN_COPY (wp, up, size);
SIZ(w) = usize;
}
显然,如果mpz_t(参见:gmp-h.in)的字段未初始化,它们可能是垃圾。 mpz_set 可以在尚未分配的连续内存上执行 realloc。如果你幸运的话,那就是一场崩溃。如果不是,程序将继续处于未定义状态。
将mpz_t 视为“C 对象”可能会很有用。在初始化之前,它们是无效的(并且不能正确使用)。我还要强调,当谈到 GMP(多精度算术)的要求时,初始化变量(例如,为零)的“开销”绝对可以忽略不计。
所以让我们假设_amount 已正确初始化:
mpz_init(_amount); /* correctly sets mpz_t and assigns (0). */
/* (maybe `_amount` isn't (0)... that's OK too) */
void f (mpz_t *_amount)
{
mpz_t amount;
mpz_init(amount);
/* unless using the GMP C++ interface, there's no definition
* for the (!) operator. However `mpz_sgn` can be used here: */
if (mpz_sgn(_amount) == 0) /* (_amount == 0 : exit condition?) */
{
mpz_clear(_amount); /* free space occupied by (_amount) */
/* NOTE: this is NOT C++ with object unwinding! (amount) will
* potentially leak resources! */
mpz_clear(amount);
throw std::bad_alloc {}; /* no leaks; deallocated storage. */
}
/* since (amount) will need to be deallocated, and we don't want
* to deal with assignment errors - we simply 'swap' contents. */
mpz_swap(_amount, amount); mpz_clear(amount);
}
我觉得你在这里混合了范式。 throw 在本质上是 C 代码中的使用会迫使您手动清理,而 mpz_t 不是不是一个 C++ 对象,它“构造”为默认值,或者在销毁时释放所有资源/ 超出范围。
您可能会发现GMP C++ interface 更适合对您的代码进行原型设计。 mpz_class 充当 C++ 类,在实例化时进行初始化,并在其作用域结束时调用它的析构函数。
现在您正在错误地混合 C/C++,并且让自己容易受到许多错误的影响,其中一些可能不会立即导致崩溃 - 这些可能是最难确定的...