代码之家  ›  专栏  ›  技术社区  ›  the_naive

C++:通过嵌套类动态分配数组时出现堆错误?

  •  -1
  • the_naive  · 技术社区  · 11 年前

    我正在为分配内存 Uint8 通过嵌套类键入数组。当我这样做的时候,我认为它会出现堆错误,并提示窗口显示 调试断言错误。表达式:_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;
    }
    

    你能发现我犯了什么错误吗?

    谢谢

    3 回复  |  直到 11 年前
        1
  •  2
  •   Community CDub    7 年前

    在构造函数中复制对象时:

    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
  •  1
  •   Glorfindel Doug L.    2 年前

    正如评论和其他人已经提到的那样,问题的出现是因为你没有遵循 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
  •  0
  •   Ivan Ishchenko    11 年前

    在里面 subTest f(test(5)); 你创建了一个临时 test 对象,将其复制到 f . f 包含temp的副本 测验 具有的副本的对象 b 指针。临时对象析构函数,指针无效。在临时(已销毁)对象中以及它的复制中 f . f.h.b[i] = ... 繁荣!堆损坏。你需要的是shared_ptr。从…起 C++11 或来自 boost .