【问题标题】:Heap corruption detected after normal block正常阻塞后检测到堆损坏
【发布时间】:2012-07-26 19:00:50
【问题描述】:

我有以下代码,但不确定为什么在遇到 Myclass 的析构函数时会收到堆损坏检测错误。我相信我正在正确地释放内存??

#include <iostream>
#include <vector>
using namespace std;

class MyClass{
private:
    char* mp_str;
public:
    MyClass():mp_str(NULL){}
    ~MyClass(){
        delete [] mp_str;
    }

    void setString(const char* str);
    void printString();
};

int main(){
    MyClass* a = new MyClass();
    std::vector<MyClass> myVector;

    myVector.push_back(*a);

    a->setString("Hello World");
    myVector[0].setString("Goodbye world");

    a->printString();
    myVector[0].printString();

    return 1;
}

void MyClass::setString(const char* const str){
    if(!str)
        return;

    size_t len = strlen(str);

    if(!this->mp_str){
        this->mp_str = new char[len];
        memset(mp_str, 0, len+1);
    }
    strncpy(mp_str, str, len);
}

void MyClass::printString(){
    if(this->mp_str)
        cout << mp_str;
    else
        cout << "No string found";
}

编辑:(固定代码)

void MyClass::setString(const char* const str){
    if(!str)
        return;

    size_t len = strlen(str);

    if(!this->mp_str){
        this->mp_str = new char[len+1];
        memset(mp_str, 0, len+1);
    }
    strncpy(mp_str, str, len);
}

在main()中,我也加了

delete a;

调用return 1之前;

【问题讨论】:

  • 需要Rule of Three
  • @yurikilochek:同意。解决了这个问题。
  • @user315052:是的,我知道a 的副本被推送到向量上,我需要在这里进行深层复制。我应该遵循三法则。但是,代码不应抛出此类错误。拉斐尔的回答帮我指出了错误!
  • @brainydexter:如果我确定这是您崩溃的根本原因,我会发布一个答案。作为评论,它表示您应该遵循的建议(因为如果不修复,以后会导致类似的挠头)。问候
  • @user315052 感谢您发布链接(因此 +1 :) 并引导我朝着正确的方向前进。我意识到这里发生的浅拷贝应该被修复。在我继续这样做之前,我在想,为什么这该死的东西会在我身上哭泣和崩溃。 :) 一个 len+1 让我到了那里!不过,谢谢!

标签: c++ memory memory-leaks


【解决方案1】:

您需要分配字符串的长度+1,以考虑空值。你做对了。

if(!this->mp_str){
    this->mp_str = new char[len+1];
    memset(mp_str, 0, len+1);
}

【讨论】:

  • 我同意@Rafael!唉,我没看到这个:(
  • @brainydexter 请注意,这不是唯一的错误。见上面的 cmets(这应该是真正的答案)
【解决方案2】:

(在 Rafael 的回答被接受后发布,应该如此。)

缓冲区溢出绝对是这次特定崩溃的根本原因,但可以通过简化实现同时调整以遵守Rule of Three 来避免崩溃。也就是说,既然你实现了一个析构函数(处理mp_str),你也应该实现一个复制构造函数和一个赋值运算符。

但是,遵守 TRoT 的另一种方法是完全避免需要实施任何这些事情。在这种情况下,使用 std::string 而不是 char * 既可以解决崩溃问题,也可以符合 TRoT:

class MyClass{
private:
    std::string mp_str;
public:
    void setString(const char* str) { mp_str = str ? str : ""; }
    void printString() {
        if (mp_str.size()) std::cout << mp_str;
        else std::cout << "(mp_str is empty)";
    }
};

【讨论】:

  • 是的,我(重新)阅读了您发布的 TROT 链接。我有一段时间没有练习过指针的乐趣了,所以我想我会再试一试这些东西。使用像 string 这样的类真的让你的生活变得轻松。
  • 虽然有时你必须编写原始 C!
  • @BrianReinhold:智能指针比原始指针更受欢迎,并且仍然可以让代码保持 RoT 兼容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 2011-07-24
相关资源
最近更新 更多