2009-09-07 3 views
6

В моем приложении используется большое количество 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; 
    } 
} 

Может ли вы предвидеть любые проблемы со второй конструкцией, кроме возросшего усилия по техническому обслуживанию? Является ли это приемлемым шаблоном дизайна или просто преждевременной оптимизацией, которая могла бы снова укусить меня?

+0

Это кусается. И он сильно укусит. –

+1

Вы нарушаете большую часть семантики для типов классов в C++. Объекты переменной длины не существуют в C++. – jalf

+2

Если вы заинтересованы в таких эффектных масках, вы можете также взглянуть на шаблоны классов TBuf8 и TBuf16 с Symbian/C++. –

ответ

9

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 и бамбук в непрерывной памяти можно использовать раствор из this article. Основная идея - перегрузить operator new и operator delete.

+0

Вы должны знать о побочных эффектах этого типа решений и проблемах, с которыми вам придется иметь дело: пользователи не смогут использовать объекты внутри контейнеров (в частности std :: vector, которые предопределяют память в зависимости от размера тип, переданный в). Этот обман приведет к коду, который не только трудно поддерживать (вопросник знает), но и неестественно использовать –

+0

Наиболее естественным является использование 'std :: vector'. Все другие решения имеют очень ограниченное применение и должны применяться с осторожностью. –

+0

Если я не ошибаюсь, строковая реализация GCC использует этот тип обмана. Хитрость заключается в том, что объект Panda может содержать единственный указатель на класс (общий класс). – UncleBens

1

Вы используете «новый» вид нового оператора. Это полностью правильная относительная Panda, но почему вы не используете Bamboo initializer?

4

Вы будете укушены, если кто-то возьмет панду по значению, например.

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

Это может быть приемлемо (но очень вероятно, преждевременно и ужасно оптимизации), если вы только когда-либо относятся к вещам, по указателю и никогда не по значению, и если вы берегитесь конструктор копирования и оператор присваивания.

3

Основываясь на моем опыте, преждевременная оптимизация всегда всегда «преждевременна». То есть вы должны профилировать свой код и определять, нужно ли оптимизировать или нет, или просто создаете больше работы для себя в долгое время.

Кроме того, мне кажется, что вопросы о том, стоит ли оптимизация или нет, сильно зависят от размера класса Bamboo и среднего количества бамбуковых объектов на Panda.

3

Это было найдено в C.
Но в C++ нет настоящей необходимости.

Реальный вопрос, почему вы хотите это сделать?

Это преждевременная оптимизация, просто используйте std :: vector <> внутренне, и все ваши проблемы исчезнут.

Поскольку вы используете RAW указатель внутри, что класс владеет вам нужно будет переопределить версии по умолчанию:

  • По умолчанию Конструктор
  • Destructor
  • конструктор копирования
  • оператора Назначение
7

Как убедить людей в простоте программирования и ясность - вкратце: то, что математики называют «элегантностью», - это не роскошь роскоши, а решающий вопрос, который решает между успехом и неудачей?

- Дейкстр

+0

Просто нет. Многие вещи могут пойти не так ... как вы собираетесь реализовать конструкторы копирования, назначение, деструкторы? Как вы собираетесь иметь дело с пользователями, которые хотят иметь массивы Panda? –

+0

Математики понятия не имеют о программировании и реальном мире. – Lothar

2

Если вы что отчаянный, вы, вероятно, можете сделать что-то вроде этого:

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

Но я верю, что вы не отчаянными, но оптимизировать преждевременно.

Смежные вопросы