2009-07-24 15 views
17

Jedną z rzeczy, która mnie myliła podczas nauki C++ (i Direct3D, ale jakiś czas temu) jest to, kiedy powinieneś użyć elementu wskaźnika w klasie. Na przykład, można użyć oświadczenie nie palików:C++ - kiedy powinienem użyć elementu wskaźnika w klasie

private: 
    SomeClass instance_; 

Albo mógłbym użyć deklarację ruchy wskaźnika

private: 
    Someclass * instance_ 

a następnie użyć new() na nim w konstruktorze.

Rozumiem, że jeśli SomeClass może pochodzić z innej klasy, obiektu COM lub jest ABC, wówczas powinien być wskaźnikiem. Czy są jakieś inne wytyczne, o których powinienem wiedzieć?

Odpowiedz

17

Wskaźnik ma następujące zalety:

a) Można zrobić leniwe inicjowanie, czyli init/utworzyć obiekt tylko krótki przed pierwszym prawdziwym użytkowania.

b) Projekt: jeśli używasz wskaźników dla członków zewnętrznego typu klasy, możesz umieścić deklarację przekazania powyżej klasy, a zatem nie musisz uwzględniać nagłówków tego typu w nagłówku - zamiast tego dołączasz nagłówki stron trzecich do pliku .cpp - ma to tę zaletę, że skraca czas kompilacji i zapobiega efektom ubocznym, włączając zbyt wiele innych nagłówków.

class ExtCamera; // forward declaration to external class type in "ExtCamera.h" 

class MyCamera { 
public: 
    MyCamera() : m_pCamera(0) { } 

    void init(const ExtCamera &cam); 

private: 
    ExtCamera *m_pCamera; // do not use it in inline code inside header! 
}; 

c) wskaźnik może być w każdej chwili usunięte - więc masz większą kontrolę o livetime i może ponownie utworzyć obiekt - na przykład w przypadku awarii.

+2

Do leniwego inicjowania, polecam używanie 'boost :: optional' kiedy tylko to możliwe. Jest bezpieczniejszy niż wskaźnik, ponieważ nie można na nim wykonywać arytmetyki. –

+1

Ale wielu (jak ja) nie używa Boost - więc jest to bardzo niezależna platforma i framework ;-) ... Ja na przykład używam tylko Qt :-) – 3DH

+1

Ale te, które nie używają 'boost' powinny :) – GManNickG

10

Przydziel to na stosie, jeśli możesz, z darmowego sklepu, jeśli musisz. Jest tutaj similar question, gdzie znajdziesz wszystkie "dlaczego".

Powodem, dla którego widzisz dużo użycia wskaźnika, jeśli chodzi o gry i takie rzeczy, jest to, że DirectX jest interfejsem COM, i szczerze mówiąc, większość programistów gier z tamtych czasów nie jest naprawdę programistami C++, oni są C- z programistami klasy, a użycie wskaźnika C jest bardzo powszechne.

17

Zalety używania wskaźnika są przedstawione przez 3DH: inicjalizacja leniwy, redukcja zależności nagłówków i kontrola nad czasem życia obiektu.

Są także wady. Kiedy masz element danych wskaźnika, prawdopodobnie musisz napisać własny konstruktor kopii i operator przypisania, aby upewnić się, że kopia obiektu jest tworzona poprawnie. Oczywiście musisz również pamiętać, aby usunąć obiekt z destruktora. Ponadto, jeśli dodasz element danych wskaźnika do istniejącej klasy, musisz pamiętać o aktualizacji konstruktora kopiowania i operatora =. W skrócie, posiadanie elementu wskaźnika danych jest dla ciebie więcej pracy.

Inną wadą jest odwrotna strona kontroli nad czasem życia obiektu wskazywanego przez wskaźnik. Elementy danych innych niż wskaźniki są niszczone automatycznie, gdy obiekt jest niszczony, co oznacza, że ​​zawsze można mieć pewność, że istnieją tak długo, jak obiekt istnieje. Za pomocą wskaźnika musisz sprawdzić, czy jest to nullptr, co oznacza, że ​​musisz zawsze ustawić go na nullptr, gdy nic nie wskazuje. Konieczność radzenia sobie z tym wszystkim może łatwo doprowadzić do błędów.

Wreszcie dostęp do elementów innych niż wskaźnik może być szybszy, ponieważ są one ciągłe w pamięci. Z drugiej strony dostęp do elementu danych wskaźnika wskazującego obiekt przydzielony na stercie prawdopodobnie spowoduje brak pamięci podręcznej, co spowalnia.

Nie ma jednej odpowiedzi na twoje pytanie. Musisz spojrzeć na swój projekt i zdecydować, czy zalety elementów danych wskaźnika przeważają nad dodatkowym bólem głowy. Jeśli skrócenie czasu kompilacji i zależności nagłówka jest ważne, użyj pimpl idiom. Jeśli twój element danych może nie być konieczny dla twojego obiektu w niektórych przypadkach, użyj wskaźnika i przydziel go w razie potrzeby. Jeśli nie brzmią jak ważne powody i nie chcesz wykonywać dodatkowej pracy, nie używaj wskaźnika.

3

Innym powodem używania wskaźników jest dynamiczne wiązanie. Jeśli masz klasę podstawową z metodą wirtualną i niektórymi klasami pochodnymi, możesz uzyskać tylko powiązanie dynamiczne za pomocą wskaźników.

+2

To nie jest w porządku - możesz mieć dynamiczne powiązanie z referencjami. – boxofrats

+1

To prawda, dziękuję za wyjaśnienia. –

Powiązane problemy