【问题标题】:Destructor deleting memory premature析构函数过早删除内存
【发布时间】:2016-02-16 05:39:32
【问题描述】:

我对 C++ 中的内存管理很陌生。我创建了一个 BigInt 类,除了影响程序性能的析构函数外,它现在已完全实现。但是,当我尝试实现析构函数时,我的程序崩溃了。

在下面的 BigInts 乘法代码中:

BigInt& BigInt::operator*=(BigInt const& other) {

    //copy of this and other
    BigInt* tempThis = new BigInt(*this); //1st number
    BigInt* tempOther = new BigInt(other); //2nd number

    //create temps so we can use value of BigInt before it is changed
    BigInt* sum = new BigInt(0); //holds the eventual answer

    BigInt* i = new BigInt(0);

    //add *this BigInt to sum otherTemp amount of times
    //this will yield multiplication answer.
    for (*i; *i < *tempOther; *i = *i + 1) {
        *sum += *this;
    }

    *this = *sum;

    return *this;

}

在 for 循环中调用 *i = *i + 1 时调用析构函数,然后我认为它在我的析构函数中被删除,如下所示:

// destructor
BigInt::~BigInt() {
    delete[] this->bigIntVector;
}

// copy constructor
BigInt::BigInt(BigInt const& orig)
    : isPositive(orig.isPositive)
    , base(orig.base)
{
    this->bigIntVector = new BigIntVector(*(orig.bigIntVector));
}

一旦 'i' 被删除,就没有任何效果,整个程序就会中断。

如果有人能给我一些关于析构函数以及如何解决我的问题的指示,那将是很大的帮助。谢谢。

【问题讨论】:

  • C++ 不是 Java。该函数充满了内存泄漏。为什么你在这么多地方使用new(而不是一次调用delete)?为什么不使用复制构造函数(你应该写的)来创建临时 BigInt 的?
  • 例如,这个:BigInt* tempThis = new BigInt(*this); //1st number 应该是这个:BigInt tempThis = *this; 和这个:BigInt sum(0);,而不是你现在拥有的。如果这不能正常工作,那么您需要退后一步并正确实现复制构造函数(以及赋值运算符)。
  • 析构函数没问题。没有什么问题。 错误的是您没有实现正确的复制构造函数和赋值运算符。换句话说,需要遵守“3 规则”。
  • 不,它不包括它。如果你想要证明:{ BigInteger b(10); BigInteger b2(20); b = b2;} 试试,当退出 { } 块时,你会看到双重删除错误和内存泄漏。

标签: c++ memory memory-management destructor bigint


【解决方案1】:

在 C++ 中,同样的(可怕的)算术可以实现如下。

BigInt& BigInt::operator*=(BigInt const& other)
{
  if(other==0)
    return other;
  if(other> 1)
    for(BigInt old=*this,i=1; i!=other; ++i)
      operator+=old;
  else if(other<0) {
    BigInt old=*this;
    *this=0;
    for(BigInt i=0; i!=other; --i)
      operator-=old;
  }
  return*this;
}

假设int 的构造函数、复制构造函数、增量operator++ 和加法operator+= 都正确实现(以及析构函数)。

很遗憾,您未能向我们提供更多信息,但您的复制构造函数和析构函数肯定坏了:

this->bigIntVector = new BigIntVector(*(orig.bigIntVector));

后面是

delete[] this->bigIntVector;

给你未定义的行为(使用new 分配,但使用delete[] 取消分配——delete[] 用于分配new[] 的内存)。我怀疑您打算在复制构造函数中从原始内存中复制内存。但是,你没有。如果

class BigInt {
  size_t    size=0;                // number of some_types allocated
  some_type*bigIntVector=nullptr;  // ptr to memory allocated, if any
  /* rest of class */
};

那么复制构造函数可以像这样实现(假设size 是非静态的)

BigInt::BigInt(BigInt const&orig)
: size(orig.size()                                   // copy size
, bigIntVector(size? new some_type[size] : nullptr)  // allocate memory
{ std::memcpy(orig.bigIntVector, bigIntVector); }    // copy memory

但是,(几乎)相同的操作可以更容易地实现

class BigInt
{
  std::vector<some_type> bigIntVector;
public:
  BigInt(BigInt const&) = default;
  BigInt(BigInt &&) = default;
  BigInt&operator=(BigInt const&) = default;
  BigInt&operator=(BigInt &&) = default;
  / * rest of class */
};

当复制和移动构造函数(以及相应的赋值运算符)为您自动正确创建时。你只需要寻址默认构造函数,例如

BigInt::BigInt()                    // default constructor
: bigIntVector(1,some_type(0)) {}   // size=1, value=0

以及内置整数类型的构造函数。如果您是 C++ 新手,请避免使用 newdelete,而使用标准库容器。

【讨论】:

  • 一旦你不再是 C++ 新手,避免 99% 或更多你认为使用 newdelete 的地方,通常有利于标准容器......
猜你喜欢
  • 2013-10-04
  • 2014-12-27
  • 2017-07-06
  • 1970-01-01
  • 2021-04-04
  • 2023-03-15
  • 1970-01-01
  • 2012-08-11
  • 2013-04-27
相关资源
最近更新 更多