【问题标题】:C++: Heap error when dynamically allocating array through nested class?C++:通过嵌套类动态分配数组时出现堆错误?
【发布时间】:2013-10-26 00:42:26
【问题描述】:

我正在尝试通过嵌套类为Uint8 类型数组分配内存。当我这样做时,我认为它会运行到堆错误并提示显示 Debug Assertion Error 的窗口。表达式:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)。我的代码如下:

#include <iostream>
#include "dcmtk/dcmdata/dctk.h"
using namespace std;

class test
{
public:
    int a;
    Uint8 * b;
    test()
    {}
    test(int c)
    {
        a=c;
        b = new Uint8[a];
    }
    ~test()
    {
        delete [] b;
    }
};

class subTest
{
public:
    test h;
    subTest()
    {}
    subTest(test g)
    {
        h=g;
    }
    ~subTest()
    {
    }
};

int main()
{
    subTest f(test(5));
    for(int i=0; i<5; i++)
    {
        f.h.b[i] = Uint8((i*2)+1);
        cout<< int(f.h.b[i])<<endl;
    }

    return 0;
}

你能找出我做错了什么吗?

谢谢。

【问题讨论】:

  • rule of three 开始。更好的是,使用std::vector&lt;Uint8&gt;
  • 我的错误我忘了提到错误。问题现已更新。
  • 也许该规则必须升级为四规则,使用移动构造函数...

标签: c++ arrays dynamic-arrays dynamic-allocation


【解决方案1】:

当你在构造函数中复制一个对象时:

subTest(test g)
{
    h=g;
}

并且一个对象包含一个类似于test class 情况的指针,您需要在自己指定的copy constructor 中进行深度复制:分配新的存储空间并将数组内容复制到其中。否则,您最终会得到两个(或以后可能更多)带有指向同一内存的对象。这就是为什么

~test()
{
    delete [] b;
}

将导致错误(此外它是未定义的行为)。附带说明:您还应该看看“三法则”。

Rule of three

What happens when you deallocate a pointer twice or more in C++?

【讨论】:

    【解决方案2】:

    正如 cmets 和其他人已经提到的那样,出现问题是因为您没有遵循 rule of three,也就是说,由于您必须定义自定义析构函数(删除动态分配的内存),您至少应该定义一个自定义复制构造函数(它执行数组的深层复制,即它分配新内存并复制旧数组的内容)和一个自定义复制赋值运算符(本质上是相同的,所以你可以在对方的条款)。

    复制构造函数的示例代码(当然不是最理想的):

    test(const test &other)
    {
      a=other.a
      b=new Uint8[a];
      for(size_t i=0;i<a;++i)
        b[i]=other.b[i];
    }
    

    可以看出,这将涉及一些工作并且非常乏味,这就是为什么您应该遵循 rule of zero 并使用已经在本质上处理所有权问题的类(在您的情况下,这可能应该是一个 std ::vector),因此不要直接处理动态分配的数组,而是将其更改为类似于以下内容:

    class test
    {
      public:
      std::vector<Uint8> b;
    
      test(int size)
      {
        b.resize(size);
      }
    }
    

    您的所有问题都消失了,因为 std::vector 自己处理所需的深拷贝,而您的班级不必担心。

    我希望这会有所帮助;-)

    【讨论】:

      【解决方案3】:

      subTest f(test(5)); 中创建一个临时test 对象,将其复制到f 中。 f 包含临时 test 对象的副本和 b 指针的副本。临时对象破坏,指针无效。无论是在临时(已销毁)对象中,还是在 f 中的副本。 f.h.b[i] = ... 轰隆隆!堆损坏。你需要的是shared_ptr。来自C++11 或来自boost

      【讨论】:

      • 那么,避免繁荣的解决方案是什么?
      • 啊哈!我刚刚删除了delete [] b; 并在外面手动删除它,这改进了它。这足以避免爆炸吗?
      • 是的,你会避免爆炸。我建议您实现复制构造函数以进行测试并以某种方式解决 b 所有权。例如,您可以创建一个新的并将其复制到那里。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 2011-07-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多