-1

我正在尝试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;
}

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

谢谢。

4

3 回答 3

2

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

subTest(test g)
{
    h=g;
}

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

~test()
{
    delete [] b;
}

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

规则三

在 C++ 中释放指针两次或更多次时会发生什么?

于 2013-10-17T13:51:43.590 回答
1

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

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

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

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

class test
{
  public:
  std::vector<Uint8> b;

  test(int size)
  {
    b.resize(size);
  }
}

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

我希望这有帮助 ;-)

于 2013-10-17T14:05:56.237 回答
0

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

于 2013-10-17T13:39:50.960 回答