可变长度的物体:永远是个好主意?

时间:2009-09-07 16:22:57

标签: c++ design-patterns data-structures class-design

我的应用程序使用大量Panda个对象。每个Panda都有一个Bamboo个对象列表。初始化Panda后,此列表不会更改(未添加或删除Bamboo个对象)。目前,我的课程实现如下:

class Panda
{
    int a;
    int b;
    int _bambooCount;
    Bamboo* _bamboo;

    Panda (int count, Bamboo* bamboo)
    {
        _bambooCount = count;
        _bamboo = new Bamboo[count];

        // ... copy bamboo into the array ...
    }
}

为了减轻分配Bamboo对象数组的开销,我可以按如下方式实现这个类 - 基本上,构造方法不是通过常规构造函数创建对象,而是分配一个内存块来保存它们。 Panda对象及其Bamboo数组:

class Panda
{
    int a;
    int b;

    Panda ()
    {
        // ... other initializations here ...
    }

    static Panda *createPanda (int count, Bamboo* bamboo)
    {
        byte* p = new byte[sizeof(Panda) +
                           sizeof(Bamboo) * count];
        new (p) Panda ();

        Bamboo* bamboo = (Bamboo*)
            p + sizeof(Panda);

        // ... copy bamboo objects into the memory
        // behind the object...

        return (Panda*)p; 
    }
}

除了增加维护工作外,您能预见到第二种设计有任何问题吗?这是一种可接受的设计模式,还是仅仅是过早的优化,可能会在以后再次让我感到困惑?

7 个答案:

答案 0 :(得分:11)

C ++为您提供了另一种选择。你应该考虑使用std :: vector。

class Panda
{
    int a;
    int b;
    std::vector<Bamboo> bamboo;
    // if you do not want to store by value:
    //std::vector< shared_ptr<Bamboo> > bamboo;

    Panda (int count, Bamboo* bamb) : bamboo( bamb, bamb+count ) {}
}

如果您想将Panda和Bamboos存储在连续内存中,您可以使用this article中的解决方案。主要想法是重载operator newoperator delete

答案 1 :(得分:7)

我们如何让人们相信编程简洁明了 - 简而言之:数学家称之为'优雅' - 不是一种可有可无的奢侈品,而是决定成败的关键因素吗?

- Edsger W. Dijkstra

答案 2 :(得分:5)

如果有人按照价值购买熊猫,你会被咬伤。

//compiler allocates 16-bytes on the stack for this local variable
Panda panda = *createPanda(15, bamboo);

如果您只是通过指针引用事物而从不通过值引用事物,并且如果您要注意复制构造函数和赋值运算符,则可能是可接受的(但很可能是过早且可怕的优化)。

答案 3 :(得分:3)

根据我的经验,过早优化总是“过早”。也就是说,您应该分析您的代码并确定是否需要优化,或者您只是为自己创建更多的工作运行

另外,在我看来,关于优化是否值得的问题在很大程度上取决于Bamboo类的大小和每个Panda的Bamboo对象的平均数量。

答案 4 :(得分:3)

这是在C.中找到的 但是在C ++中并没有真正的需要。

真正的问题是你为什么要这样做?

这是一个不成熟的优化,只需使用std :: vector&lt;&gt;在内部,你所有的问题都将消失。

因为您在内部使用该类所拥有的RAW指针,所以您需要覆盖默认版本:

  • 默认构造函数
  • 析构函数
  • 复制构造函数
  • 作业运算符

答案 5 :(得分:3)

如果你是绝望的,你可能会做这样的事情:

template<std::size_t N>
class Panda_with_bamboo : public Panda_without_bamboo
{
    int a;
    int b;
    Bamboo bamboo[N];
}

但我相信你并不是绝望,而是过早地进行优化。

答案 6 :(得分:1)

您使用新操作员的“新”外观。相对Panda完全正确,但为什么不使用Bamboo初始化器?