【问题标题】:HEAP CORRUPTION DETECTED : after normal block ()HEAP CORRUPTION DETECTED : 在正常块 () 之后
【发布时间】:2015-01-10 01:55:13
【问题描述】:

所以,我定义了模板类,然后尝试重载一些运算符。

 template <typename  T> class Set
    {
    public:
        Set(void);
        Set(Set&);
        ~Set(void);
        bool contains(T elem);
        bool add(T elem);
        bool remove(T elem);
        bool add(T* tab, int size);
        T* getSet();
        int size();
        Set<T> &operator+(Set<T> &snd);
        Set<T> &operator-(Set<T> &snd);
    private:
        T *elements;
        int numOfElem;
    };

当我尝试通过 add 方法向 Set 添加元素时,一切正常。

template<typename T>
    bool Set<T>::add(T elem)
    {
        bool found = false;
        for(int i =0; !found && i<numOfElem; i++){
            if(elem == elements[i]) found = true;
        }
        if( !found ){
            numOfElem++;
            T* tmp = new T[numOfElem];
            for(int i =0;  i<numOfElem-1; i++){
                tmp[i] = elements[i];
            }
            tmp[numOfElem-1] = elem;
            delete[] elements;
            elements = tmp;
        }
        return !found;
    }

    template<typename T>
    bool Set<T>::add(T* myArray, int size)
    {
        bool result = false;
        for(int i =0;  i<size; i++){
            add(myArray[i]);
        }
        return result;
    }
template<typename T> 
Set<T>& Set<T>::operator+(Set<T> &snd)
{
    Set *temp = new Set(*this);
    temp->add(snd.getSet(), snd.size());
    return *temp;
}
template<typename T> 
void Set<T>::operator=(Set<T> &snd)
{
    numOfElem = snd.numOfElem;
    elements = new T[numOfElem];
    for(int i =0; i < numOfElem; i++){
        elements[i] = snd.elements[i];
    }
}

template<typename T>
int Set<T>::size()
{
    return numOfElem;
}
template<typename T> 
T* Set<T>::getSet()
{
    return elements;
}
template<typename T>
Set<T>::Set()
{
  numOfElem = 0;
  elements = nullptr;
}

template<typename T>
Set<T>::Set(Set& old)
{
  numOfElem = old.numOfElem;
  elements = new T(numOfElem);
  for(int i = 0; i< numOfElem; i++){
      elements[i] = old.elements[i];
  }

}

template<typename T>
Set<T>::~Set()
{
  numOfElem = 0;
  delete[] elements;
  elements = nullptr;
}

但如果我改用 + 运算符(添加两个单独的集合),则会在尝试删除数组(15 行)时发生错误。有什么想法吗?

int main(){
    Set <char> set1, set2, set3;
    char tab[] = {'a','d','f','g'} ;
    set1.add(tab, 4);
    char tab2[] = {'a','d','x','y','z'} ;
    set2.add(tab2,5);
    set3= set1+set2;
}

【问题讨论】:

  • 返回对本地对象的引用绝不是明智的。你应该听过编译器的警告(return temp 来自operator+)。把签名改成template&lt;typename T&gt; Set&lt;T&gt; Set&lt;T&gt;::operator+(Set&lt;T&gt; &amp;snd),没人受伤。
  • @PiotrSzymczyk “好的,好点子,但它并没有解决问题。” 好吧,应该给@987654321 @为您的问题,而不是拒绝建议,并等待其他用户调试您的代码!不幸的是,出于不同的原因,我一直在对您的问题进行近距离投票,但实际上您是在问一个重复的问题:Can a local variable's memory be accessed outside its scope?。我应该把你的问题放在第一位。
  • 我猜是双重删除。如果你有一个原始指针,你需要考虑三法则。我只看到两个。 stackoverflow.com/questions/4172722/what-is-the-rule-of-three
  • 对不起,这是我在这里的第一篇文章,我已经更新了代码 (MCVE) 以表明问题确实存在。复制赋值运算符也没有帮助。
  • 你想在这里使用括号[]吗? elements = new T(numOfElem); 如果您将所有代码放在一个块中以便可以轻松复制/粘贴,并且如果您使用代码格式化按钮,而不是 sn-ps 按钮来格式化代码,这将有助于任何试图实际运行您的代码的人.

标签: c++ templates overloading heap-corruption


【解决方案1】:

你的复制构造函数有错误:

elements = new T(numOfElem);

应该是

elements = new T[numOfElem];

通过编写new T(numOfElem);,您只分配了一个变量,其值初始化为 numOfEllem。

使用 std::vector 代替数组可以避免此类问题。

您的代码还在加法运算符中泄漏了内存:

template<typename T> 
Set<T>& Set<T>::operator+(Set<T> &snd)
{
    Set *temp = new Set(*this);
    temp->add(snd.getSet(), snd.size());
    return *temp;
}

您正在分配内存并且您永远不会删除它,因此如果您过于频繁地调用该函数,您的程序可能会耗尽其虚拟内存并会因未捕获的 std::bad_alloc 异常而崩溃。把函数改成这样:

template<typename T>
Set<T> Set<T>::operator+(Set<T> &snd)
{
    Set temp(*this);
    temp.add(snd.getSet(), snd.size());
    return temp;
}

【讨论】:

  • 交换假定操作系统具有由文件系统支持的虚拟内存。虽然很常见,但这并不是严格强制性的。假设虚拟内存,应用程序通常会耗尽地址空间,而不是内存。您的结论同样错误:交换不会影响系统稳定性。并且泄漏内存不会导致交换:该内存最终会被分页,并且由于您没有对它的引用,因此它将永远不会再次被分页。您可能希望完全修改(或删除)该段落。
  • 我通过交换删除了该部分,因为它使用了不准确的术语。我的意思是,当您在 64 位程序中无限循环运行该添加时,您的物理操作内存的大小比地址空间的大小小得多,因此操作系统将不得不将大量页面交换到磁盘和在此期间操作系统可能会变得不稳定(我确实在 Windows 7 上对其进行了测试,但我不得不重置计算机)。当磁盘上的交换达到最大容量或程序的虚拟内存已满时,程序最终会崩溃,但这需要很长时间,除非你有 SSD 磁盘。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
相关资源
最近更新 更多