2012-07-26 104 views
5

我有下面的代码,我不知道为什么当它遇到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"; 
} 

EDIT:(固定代码)

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); 
} 
在主

(),我还添加

delete a; 

调用返回1之前;

+5

需要的【三规则(http://stackoverflow.com/questions/4172722/what-是最规则的三)。 – jxh 2012-07-26 19:03:04

+3

你也泄漏'a'中的对象 – 2012-07-26 19:03:49

+0

@yurikilochek:同意。固定的。 – brainydexter 2012-07-26 19:08:10

回答

8

您需要分配字符串+1的长度来解决null。你是正确的memsetting。

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

我同意@Rafael!叹气,我没有看到这一个:( – brainydexter 2012-07-26 19:07:29

+0

@brainydexter请注意,虽然这并非唯一的错误。请参阅上面的评论(这应该是真正的答案) – 2012-07-26 19:07:59

+0

@KonradRudolph同意。 – brainydexter 2012-07-26 19:16:09

1

(发布拉斐尔的答案被接受后,理所应当的。)

缓冲区溢出肯定这种崩溃的根本原因,但可避免通过简化的实施而崩溃调整为遵守Rule of Three。换句话说,既然你实现了一个析构函数(为了处理mp_str),你还应该实现一个拷贝构造函数和一个赋值操作符。但是,坚持使用TRoT的另一种方式是避免需要实施任何这些东西。在这种情况下,使用std::string代替char *会解决了这两个碰撞并符合小跑:

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)"; 
    } 
}; 
+0

是的,我(重新)读那个链接到你发布的TROT,我在一段时间内没有练习过一些指针,所以我想我会再给这些东西一个旋转的东西,使用像string这样的类真的让你的生活变得简单 – brainydexter 2012-07-26 19:39:02

+0

虽然有时你必须写生C! – 2016-08-20 12:59:11

+0

@BrianReinhold:智能指针会优于原始指针,并且仍然会让代码保持符合RoT的规范。 – jxh 2016-08-23 17:43:11