0

我正在构建一个名为 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()”并为对象提供一些虚拟值,然后将它们设置为所需的值,但这样做我感到不舒服,因为我不知道为什么我不能只是“分配空间 -> 实例化对象”。我希望我能够解释我的问题。谢谢!

4

3 回答 3

1

另一种“C++ 方式”是使用std::allocator.

它为您提供allocate并且deallocate只保留内存而不构造元素。

  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;

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

但是你必须先摧毁你的元素。如果您将 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;
    }
}
于 2013-06-22T13:32:09.713 回答
1

您可以使用您提供的大小来调用,而不是 new T获取内存并调用 ctor 。operator new唯一为您提供内存,仅此而已。然后你可以调用placement new正确计算的位置,这将只调用你的ctor。在您发布的位置上,而不是重新分配。在 google 上搜索提供的术语以查看示例。

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

于 2013-06-22T13:16:22.663 回答
0

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

于 2013-06-22T13:12:07.507 回答