2013-06-12 26 views
20

Powiedz, że mam klasę wymagającą działania kilku stałych. Kilka funkcji składowych wymaga użycia tych stałych. Użycie #define jest niezadowolone, ponieważ może powodować kolizje. Stałe są wzorami szesnastkowymi składającymi się z 8 lub 16 bitów i są przechowywane jako uint8_t lub uint16_t. Stałe te również nie zmieniają się z instancji na instancję klasy, a zatem pamięć (choć bardzo małą pamięć) można zapisać, mając tylko jedną kopię stałych.Używanie zmiennych statycznych Constellation C++

Czy jest coś niewłaściwego, lub być może lepszego sposobu realizacji wyżej zamiast po prostu robi coś jak następuje:

// mycode.h 
// ....... 
class myclass { 
private: 
    static const uint16_t kMyClassConstant_ = 0xBEEF; 
// ....... 
}; 

Dzięki z góry za pomoc.

+0

Nie, nie ma w tym nic złego. (Mam nadzieję, że niektórzy eksperci C++ nie będą musieli mnie poprawiać :)) – xxbbcc

+0

Możesz uzyskać lepsze odpowiedzi na http://codereview.stackexchange.com. –

+2

Tak, jest to normalny sposób deklarowania stałej globalnej. –

Odpowiedz

38

Biorąc pod uwagę twój opis sytuacji, powiedziałbym, że używanie static const członków jest dobrym podejściem. W C++ 11 możesz go zmienić na static constexpr, aby podkreślić, że jest to stała czasu kompilacji, chociaż nic nie zmieni się w rezultacie.

Jeśli odnosić się do myclass::kMyClassContant_ gdzieś w kodzie w sposób, który jest istotny w ramach reguły jednej definicji (odr), esp. w kontekstach wymagających odniesienia (w tym const-reference) kompilator będzie narzekał, że nie ma definicji stałej. Samo zadeklarowanie i zainicjowanie go wewnątrz klasy nie jest w tym przypadku wystarczające. To może zmusić cię do oddzielnej deklaracji i definicji:

// mycode.h 
class myclass { 
private: 
    static const uint16_t kMyClassConstant_; 
}; 

// mycode.cpp 
const uint16_t myclass::kMyClassConstant_ = 0xBEEF; 

Aby uniknąć kłopotów z utrzymaniem oddzielnych deklaracji i definicji, niektórzy ludzie wolą deklarowania funkcji inline constexpr zamiast zmiennej rzeczywistej:

// mycode.h 
class myclass { 
private: 
    static constexpr uint16_t kMyClassConstant_() 
    { return 0xBEEF; } 
}; 

ten to poprawne obejście wielu problemów związanych z odrami i nie powoduje żadnych strat w wydajności. To, czy jest to naprawdę użyteczne, zależy od tego, ile obciążenia stanowi utrzymanie oddzielnych deklaracji i definicji zwykłej stałej statycznej. Jeśli spodziewasz się, że twoje stałe nigdy się nie zmienią w miarę ewolucji twojego kodu, lepiej jest użyć zwykłych stałych statycznych z oddzielnymi definicjami. Ale jeśli często modyfikujesz definicje stałych, konieczność ponownego skompilowania pliku definicji i ponownego połączenia z wszystkimi istotnymi częściami projektu może sprawić, że rozwiązanie oparte na funkcjach będzie lepszym rozwiązaniem.

Ostateczny komentarz do typu danych: Wymuszenie 16 bitów przy użyciu std::uint16_t może być przydatne, jeśli trzeba przechowywać wiele tych wartości w formie kompaktowej. W przeciwnym razie rzeczywisty rozmiar może nie mieć znaczenia, w którym to przypadku może być lepszy std::uint_fast16_t (który może być większy niż 16 bitów).

+7

Zwracam uwagę na twoje odpowiedzi w SO, i o ile mogę powiedzieć, że są najlepsze pod względem precyzji i precyzji. Kontrastuje to z niektórymi osobami o wysokiej "reputacji", które nieustannie odwołują się do mistyfikacji zamiast odpowiadać na pytania. Gratulacje (+1) – Ayrosa

+1

@ 411165 Dzięki za pochwałę :) Doceniam twoją dokładność w badaniu moich (i innych) postów SO! – jogojapan

+0

Ta odpowiedź jest całkiem przydatna, ale nie rozumiem uzasadnienia rekompilacji. Sądzę, że używając wbudowanych funkcji członków (w definicji klasy, a zatem w pliku nagłówkowym), każda zmiana wartości będzie wymagać ponownego kompilowania wszystkich klienckich jednostek tłumaczeniowych (które obejmują ten plik nagłówkowy), nawet jeśli nie mogą uzyskać bezpośredniego dostępu do tych prywatnych funkcje członka. Z drugiej strony, z osobnymi deklaracjami i definicjami, zmiana wartości zmienia tylko moduł implementacji, wymagający jednej rekompilacji i właśnie _relinkowania_ klientów. To mniej, nie więcej. –

5

Można użyć cechy typu zaimplementować to:

#include <type_traits> 

class myclass { 
private: 
    typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant; 

    // ... 
}; 

stosowany jako myclass::kMyClassConstant::value.

To pokazuje cel wprowadzenia stałej całkowej i zapobiega przypadkowemu adresowi stałej.

Powiązane problemy