【问题标题】:Heap Corruption Detected检测到堆损坏
【发布时间】:2011-07-24 17:21:14
【问题描述】:

我的程序输出唯一不正确的是有一个“!” “钓鱼”之后。我试过调试它,但从来没有'!'在记忆中。

这是这一行的输出

One more: gone down to the fishing! hole

这里是s6和s7的创建

MyString s6("gone ");
MyString s7("fishing");

这是产生语句的行

cout << "One more: " << s6 + "down to the " + s7 + " hole" << endl << endl;

这里是

ostream& operator<<(ostream& leftOp, const MyString& rightOp)
{
leftOp << rightOp.stringArray;

return leftOp;
}

这里是+运算符重载函数

MyString MyString::operator+(const char* rightOp) const
{
    MyString result; // new object used to store result
    result.stringSize = stringSize + strlen(rightOp);
    // if the string does not fit in the array
    if( result.stringSize > result.stringCap )
    {
        delete[] result.stringArray;
        result.stringCap = ( stringSize + 15 ) & ~15;
        result.stringArray = new char[stringCap + 1];
    }
    strcpy(result.stringArray, stringArray);
    strcat(result.stringArray, rightOp);
    return result;
}

s7 在程序的其他任何地方都没有调用,所以我认为不需要显示更多代码。任何帮助将不胜感激。

【问题讨论】:

  • 我应该补充一点,使用 + 运算符的每一行都可以正常工作。
  • 你能告诉我们
  • 在原帖中添加了
  • 顺便说一句,这可能不是“堆损坏”...
  • 在这一行result.stringArray = new char[stringCap + 1];,你使用什么stringCap作为结果?

标签: c++ string overloading operator-keyword


【解决方案1】:

正常情况下你没有分配stringArray,过大情况下你没有重置stringSize,strncpy更安全:

MyString MyString::operator+(const char* rightOp) const
{
    MyString result; // new object used to store result
    result.stringSize = stringSize + strlen(rightOp);
    // if the string does not fit in the array
    if( result.stringSize > result.stringCap )
    {
        delete[] result.stringArray;
        result.stringCap = ( stringSize + 15 ) & ~15;
        // don't allocate here
        result.stringSize = stringCap;
    }

    // always allocate for the new string
    result.stringArray = new char[result.stringSize + 1];

    strncpy(result.stringArray, stringArray, result.stringSize);
    strncat(result.stringArray, rightOp, strlen(rightOp) + 1);
    return result;
}

编辑:好的,忽略这个。我假设有关 MyString 类的某些事情显然并非如此。所以,这就是我现在可以指出的:

if( result.stringSize > result.stringCap )
{
    delete[] result.stringArray;
    result.stringCap = ( stringSize + 15 ) & ~15;
    result.stringArray = new char[stringCap + 1]; // WRONG stringCap!
    result.stringArray = new char[result.stringCap + 1]; // right stringCap
}

您可以尝试简化事情,缩小问题范围:

cout << "One more: " << s6 + "down to the " << s7 + " hole" << endl << endl;

也许问题出在operator+(const MyString&amp;) 而不是operator+(const char*)

【讨论】:

  • 在我看来,MyString 的默认构造函数为result.stringArray 分配了一些默认大小。如果没有,那么delete[] result.stringArray 行将删除未分配的缓冲区。假设是这种情况,此代码会在常见情况下泄漏内存。
  • 默认构造函数确实将默认大小设置为 0
  • 我假设这就是你的意思.. strncat(result.stringArray, rightOp.stringArray, strlen(rightOp.stringArray) + 1); ?
  • stringCap 被默认构造函数设置为 16。
【解决方案2】:

很难判断您的代码是否存在问题。
我会看看其他成员。 你遵守了 3 规则吗

注意:

我要指出的是,您违反了基本的 OO 规则。

除非有 very 充分的理由,否则您不应该摆弄另一个对象的成员。 在这里,您的对象正在摆弄结果。

如果你这样写代码会更干净:

MyString MyString::operator+(const char* rightOp) const
{
    MyString result(*this);   // make a copy of this.
    result += rightOp;        // Let result fiddle with its own members here.
    return result;
}

编辑:

基于以下评论。

Rule of Three

基本上:如果您的对象拥有动态分配的内存(即它调用 new/delete),那么编译器生成的方法的默认版本不会按您的意愿工作;你应该定义你自己的版本:

基本上:

* Copy Constructor
* Assignment Operator
* Destructor

* Not part of rule of 3, but you probably also need a normal constructor.

简单的事情是你可能已经有一个析构函数(否则不会损坏),并且赋值运算符可以用复制构造函数来编写。所以你需要做的就是编写一个正确版本的复制构造函数,一切都应该可以工作。

/*
 * Assignment operator using Copy and swap Idiom.
 * Copy uses copy constructor (here done in pass by value)
 *
 * You then just swap the current content with the copy
 */
MyString& MyString::operator=(MyString rhs)
{
    (*this).swap(rhs);
    return *this;
}

【讨论】:

  • Martin,问题显然不在于“漂亮的 oo 架构”。
  • @Ubiquité:正确。但是正确地编写它更有可能导致出错的机会更少。我敢打赌这个问题是由于没有正确执行三规则造成的。如果无法看到所需的方法(复制构造函数/赋值运算符/析构函数/(普通构造函数)),很难判断问题出在哪里。
  • 我不同意,对我来说“正确书写”不是“遵循 00 规则”的同义词
  • @Ubiquité:重新安排,所以我提到了我认为问题是第一个(而不是第二个)的问题。
【解决方案3】:

如果你将 stringCap 分配给你的数组,你介意 '\0' 吗?存储字符串的char*必须是大小为size-of-string + 1的数组

问题可能出在你连接两个 MyString 时。第二个字符串,fishing,可能有一个太大的 stringSize 值。

为什么不直接写result.stringCap = ( stringSize + 15 ) &amp; ~15;而不是:

result.stringCap = result.stringSize + 1;

【讨论】:

  • 将容量更改为 16 的下一个倍数
  • @bluetickk:这个result.stringCap = ( stringSize + 15 ) &amp; ~15; 不太好用。如果 stringSize 是 (0,16,32,48) 它不会改变大小。
【解决方案4】:

if( result.stringSize &gt; result.stringCap ) 应该是 if( result.stringSize &gt;= result.stringCap ) 以允许空终止。您还需要重置result.stringSize

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    相关资源
    最近更新 更多