2009-09-07 12 views
6

Moja aplikacja używa dużej liczby obiektów Panda. Każdy obiekt Panda ma listę obiektów Bamboo. Ta lista nie zmienia się po zainicjowaniu Panda (nie dodaje się ani nie usuwa obiektów). Obecnie moja klasa jest realizowany w następujący sposób:Obiekty o zmiennej długości: Czy kiedykolwiek był to dobry pomysł?

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 ... 
    } 
} 

Aby zmniejszyć obciążenie alokacji tablicę Bamboo obiektów, mogłaby wdrożyć tę klasę następująco - w zasadzie, zamiast tworzenia obiektów poprzez regularne konstruktora, konstrukcję metoda przydziela jeden blok pamięci do przechowywania zarówno obiekt Panda i jego Bamboo tablicy:

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; 
    } 
} 

Czy przewiduje żadnych problemów z drugiego projektu, inne niż zwiększonego wysiłku technicznego? Czy jest to akceptowalny wzorzec projektu, czy po prostu przedwczesna optymalizacja, która mogłaby mnie później ugryźć?

+0

Ugryzie. I będzie mocno gryźć. –

+1

Przełamujesz większość semantyki dla typów klas w C++. Obiekty o zmiennej długości nie istnieją w C++. – jalf

+2

Jeśli interesują Cię fascynujące sztuczki tego typu, możesz również zapoznać się z szablonami klas TBuf8 i TBuf16 z Symbian/C++. –

Odpowiedz

9

C++ daje inną opcję. Powinieneś rozważyć użycie 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) {} 
} 

Jeśli chcesz przechowywać Panda i bambus w ciągłej pamięci można wykorzystać rozwiązania z this article. Główną ideą jest przeciążenie operator new i operator delete.

+0

Musisz zdawać sobie sprawę z efektów ubocznych tego typu rozwiązań i problemów, z którymi będziesz musiał sobie poradzić: użytkownicy nie będą mogli używać obiektów wewnątrz kontenerów (w szczególności std :: vector, który wstępnie alokuje pamięć w zależności od rozmiaru typ przekazany) Ta sztuczka kończy się na kodzie, który jest nie tylko trudny do utrzymania (pytający wie), ale nienaturalny w użyciu. –

+0

Najbardziej naturalne jest użycie 'std :: vector'. Wszystkie inne rozwiązania mają bardzo ograniczone zastosowanie i należy je stosować z zachowaniem ostrożności. –

+0

Jeśli się nie mylę, implementacja ciągów GCC używa tego rodzaju sztuczek. Sztuczka polega na tym, że obiekt Panda może zawierać pojedynczy wskaźnik do (zaimplementowanej) klasy implementacji. – UncleBens

1

Używasz "nowego" wyglądu nowego operatora. Jest to w pełni poprawna względna Panda, ale dlaczego nie używasz inicjalizatora Bamboo?

4

Zostaniesz ugryziony, jeśli ktoś wziąłby Pandę według wartości np.

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

Może być do zaakceptowania (ale jest bardzo prawdopodobnie przedwczesne i straszne optimization), jeśli tylko kiedykolwiek odnoszą się do rzeczy przez wskaźnik i nigdy przez wartość, a jeśli uwaga konstruktora kopii i operator przypisania.

3

Na podstawie mojego doświadczenia, przedwczesna optymalizacja jest najczęściej "przedwczesna". Oznacza to, że powinieneś profilować swój kod i określić, czy istnieje potrzeba optymalizacji, lub po prostu tworzysz więcej pracy dla siebie w długi bieg.

Wydaje mi się również, że pytania, czy optymalizacja jest tego warta czy nie, zależy w dużej mierze od wielkości klasy Bamboo i średniej liczby obiektów Bamboo na Pandę.

3

To było znaleźć w C.
Ale w C++ nie ma prawdziwej potrzeby.

Prawdziwe pytanie brzmi: dlaczego chcesz to zrobić?

To jest przedwczesna optymalizacja, wystarczy użyć std :: vector <> wewnętrznie i wszystkie problemy znikną.

Ponieważ używasz RAW wskaźnik wewnętrznie, że klasa posiada trzeba by zastąpić wersje domyślne:

  • konstruktor domyślny
  • Destructor
  • Konstruktor kopiujący
  • operatora przypisania
7

Jak przekonujemy ludzi, że w programowaniu prostota i jasność - w skrócie: co matematycy nazywają "elegancją" - nie są zbędnym luksusem, ale kluczową kwestią, która decyduje między sukcesem a porażką?

- Edsger Dijkstra

+0

Po prostu nie rób tego. Wiele rzeczy może pójść nie tak ... w jaki sposób zamierzasz implementować konstruktory kopiowania, zadania, destruktory? Jak sobie poradzisz z użytkownikami, którzy chcą mieć tablice Pandy? –

+0

Matematycy nie mają pojęcia o programowaniu i realnym świecie. – Lothar

2

Jeśli jesteś zdesperowany, prawdopodobnie można zrobić coś takiego:

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

Ale wierzę, że nie jesteś zdesperowany, ale optymalizacji przedwcześnie.

Powiązane problemy