在C ++中分配Object的二维数组时出错

时间:2013-06-22 13:02:33

标签: c++

我正在构建一个名为ParticleMatrix的类,它存储对象Ball的二维数组。我想为它们动态分配空间。代码看起来像这样。

/* 
 * allocateParticle takes a width w, height h, restlength RL then allocates space for
 * and constructs a 2D array of Particles of subclass Ball. 
 */ 
void ParticleMatrix::allocParticles(int w, int h, float RL)
{
    // Gets the number of particles in the xDirection
    xPart = getNrPart(w,RL);
    // Gets the number of particles in the yDirection
    yPart = getNrPart(h,RL);

    // Allocates a row of pointers to pointers.
    ballArray = new Ball*[xPart];
    // The ID of the particles.
    int ID = 0;

    // For every particle in the xDirection
    for(int x = 0; x<xPart; x++)
    {
        // Allocate a row of Ball-pointers yPart long.
        ballArray[x] = new Ball[yPart];

        // For every allocated space
        for(int y = 0; y<yPart; y++)
        {
            // Construct a Ball
            ballArray[x][y] = Ball( ID, RL*(float)x, RL*(float)y);
            ID++;
        }
    }
}

“ballArray [x] = new Ball [yPart]”行出现问题。 CodeBlocks给了我编译器错误“错误:没有匹配函数来调用'Ball :: Ball()'”。 我有4个不同签名的Ball构造函数,没有看起来像:“Ball()”。

我尝试添加一个构造函数“Ball :: Ball()”然后编译然后我觉得我应该能够为一个对象分配空间然后实例化它们。

我想知道的是:为什么我不能在上面的代码中没有构造函数“Ball :: Ball()”的情况下为对象Ball分配空间? 并且:如果在某种程度上可以在没有构造函数“Ball :: Ball()”的情况下分配空间,我将如何去做呢?

我知道我可以创建构造函数“Ball :: Ball()”并给对象一些虚拟值,然后将它们设置为所需的值,但我觉得这样做很不舒服,因为我不知道为什么我不能只是“分配空间 - &gt;实例化对象”。我希望我能够解释我的问题。谢谢!

3 个答案:

答案 0 :(得分:1)

而不是new T,它会获取内存并调用ctor,您可以使用您提供的大小调用operator new。唯一为你提供记忆而没有别的。然后,您可以在正确计算的位置上调用placement new,这将仅调用您的ctor。在您发布的位置而不是重新分配。在谷歌搜索提供的条款以查看示例。

但通常你不应该这样做,你可以使用std::vector<Ball>以更少的努力和更高的安全性来完成你的任务。

答案 1 :(得分:1)

这样做的另一种“C ++方式”是使用std::allocator

它为您提供allocatedeallocate,它们只保留内存而不构建元素。

  std::allocator<Ball*> ball_ptr_allocator;
  std::allocator<Ball> ball_allocator;

  Ball ** ptr = ball_ptr_allocator.allocate(10);

  for (size_t x=0; x<10; ++x)
  {
    ptr[x] = ball_allocator.allocate(10);
    for (size_t y=0; y<10; ++y)
    {
      ball_allocator.construct(&ptr[x][y], ID, RL*(float)x, RL*(float)y);
      // if you do not have access to C++11 use this:
      // ball_allocator.construct(&ptr[x][y], Ball(ID, RL*(float)x, RL*(float)y));
      ++ID;
    }

请注意以下几个问题:

  • 我通常建议对大小使用无符号类型(例如size_t)。

  • 如果您使分配器成为可以访问的成员,则可以在析构函数等中再次释放内容。 std::allocator<Ball> m_ballAlloc;

  • 您必须(以某种方式)跟踪构造的元素和分配的内存。如果其中一个构造将抛出异常,您应该能够清理构造的元素并释放分配的内存。

对于解除分配跟踪,您可以在allocParticles

中使用额外的循环
for(size_t x = 0; x<xPart; x++) ballArray[x] = nullptr;

现在你知道每个不是nullptr的ballArray[i]都需要被释放。

但是你必须先破坏你的元素。 如果你使你的ID成为类的成员变量,你可以使用它来销毁构造的元素(因为它只在构造元素后递增)。

我只针对ballArray破坏编写了一个析构函数示例,请注意,如果存在,您可能还需要处理其他资源。

~ParticleMatrix (void)
{
    // check this here and set ballArray to nullptr upon construction
    // of the ParticleMatrix
    if (ballArray != nullptr)
    {
        // start to destroy the Balls
        size_t destroycounter(0U);
        for(size_t x = 0; x<xPart; x++)
        {
            for(size_t y = 0; y<yPart; y++)
            {
                if (destroycounter < ID) 
                {
                    m_ballAlloc.destroy(&ballArray[x][y]);
                    ++destroycounter;
                }
            }
        }
        // deallocate 2nd dimension arrays
        for(size_t x = 0; x<xPart; x++) 
        {
            if (ballArray[x] != nullptr) m_ballAlloc.deallocate(ballArray[x], yPart);
        }
        // deallocate first dimension
        delete [] ballArray;
    }
}

答案 2 :(得分:0)

在C ++中,运算符new不仅为变量分配空间,还为构造。如果您没有默认构造函数Ball::Ball(),则无法构造数组中的每个对象。在C ++中没有“只是分配空间”,原则上 ...