2014-07-07 195 views
1

我试图搜索相同的问题,但没有人帮助我。当我运行程序时,出现“发生缓冲区溢出......”错误。缓冲区溢出删除[]

构造方法:

Player(char* n) 
{ 
    length = strlen(n); 
    name = new char[length+1]; 

    for(unsigned int i(0); i < length; i++) 
     name[i] = n[i]; 

    name[length] = '\0'; 
} 

Destr:

~Player(void) 
{ 
    delete [] name; 
} 

我NULL结尾的字符串,并没有得到出界,是什么问题?

+4

该类是否遵循[Rule of Three](http://stackoverflow.com/questions/4172722)?如果没有,那么你很可能会删除两次相同的缓冲区。使用'的std :: string'正确地管理动态内存给你,除非你特别想练习指针杂耍技能。 –

+2

你怎么知道它是引起问题这个特殊的代码? – Jon

+0

相关:[五规则(http://stackoverflow.com/questions/4782757/rule-of-three-becomes-rule-of-five-with-c11) – Deduplicator

回答

1

在你发布的代码中没有明显的错误,但试图通过处理原始指针来管理动态内存将几乎不可避免地导致类似的错误。

也许您没有正确实施或删除复制构造函数和复制赋值运算符,根据Rule of Three。在这种情况下,复制一个Player对象将给两个指向同一数组的指针的对象;他们都会尝试删除该数组,给出未定义的行为。

最简单的解决方案是使用专为管理字符串设计的类来管理字符串。改变name类型std::string,然后构造函数可以简单地像

explicit Player(std::string const & n) : name(n) {} 

而且也没有必要声明析构函数(或移动/拷贝构造函数/赋值运算符)在所有。

0

因此...已经提供了使用std::string的解决方案,但让我给出另一种解决方案,保持您的成员变量不变。

问题是这样的。假设你有这样的代码的地方:

Player p1("Bob"); // Okay 
Player p2("Annie"); // Okay 
p2 = p1; // Oops! (1) 
Player p3(p1); // Oops! (2) 

在(1),该方法Player& Player::operator=(const Player&)被调用。既然你没有提供,编译器会为你生成一个。当它这样做时,它只是假定它可以复制所有成员变量。在这种情况下,它复制了Player::namePlayer::length。所以,我们有p1.name == p2.name。现在调用p2的析构函数时,将删除p2.name指向的已分配内存。然后当调用p1的析构函数时,相同的内存将被删除(因为p1.name == p2.name)!这是违法的。

要解决这个问题,你可以自己写一个赋值操作符。 (2),发生同样的问题。您没有复制构造函数,因此编译器会为您生成一个。它也会假设它可以复制所有的成员变量,所以当析构函数被调用时,它们会尝试再次删除相同的内存。为了解决这个问题,也写了拷贝构造函数:

Player::Player(const Player& other) 
{ 
    if (this == &other) return; 
    length = other.length; 
    name = new char[length + 1]; 
    for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i]; 
} 

在这一天结束时,你应该使用虽然一个std::string

+0

谢谢!我太接近了这个问题,但是这个曲子读到它10分钟前我没有做;)突然发现,我没有用“删除[]”一个错误。对于不正确的问题,我很抱歉,但这些答案解决了我不知道的问题。再次感谢! – pushandpop

+0

这不是实现复制语义的最好的例子。特别是,不调用析构函数 - ,让未定义行为(即使你可能会摆脱它在这里)。我希望有合理的例外安全;如果内存分配失败,这会使分配目标留下一个悬挂指针。考虑[copy-and-swap idiom](http://stackoverflow.com/questions/3279543)使用复制构造函数进行安全赋值,而不是手动编写这两个函数。因为您正在初始化一个新对象,所以不需要在构造函数中检查相同的对象。 –