删除[]的缓冲区溢出

时间:2014-07-07 11:31:06

标签: c++ string char buffer delete-operator

我试图搜索相同的问题,但没有人帮助过我。当我运行程序时,我得到“A Buffer Overrun has occurred ...”错误。

|构造:

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终止字符串并且没有超出范围,有什么问题?

2 个答案:

答案 0 :(得分:1)

您发布的代码中没有明显错误,但尝试通过处理原始指针来管理动态内存几乎不可避免地会导致这样的错误。

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

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

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

并且根本不需要声明析构函数(或移动/复制构造函数/赋值运算符)。

答案 1 :(得分: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开始)!这是非法的。

要解决此问题,您可以自己编写一个赋值运算符。

Player& Player::operator = (const Player& other)
{
    // Are we the same object?
    if (this == &other) return *this;

    // Delete the memory. So call the destructor.
    this->~Player();

    // Make room for the new name.
    length = other.length;
    name = new char[length + 1];

    // Copy it over.
    for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i];
    name[length] = '\0';

    // All done!
    return *this;
}

在(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