2016-01-12 47 views
6

W pliku nagłówkowym globalne stałe mogą być zadeklarowane i (pre) zdefiniowane w jednym wierszu.Napowietrznych stałych statycznych, jeśli są włączone do wielu jednostek tłumaczeniowych?

// constants.h 
namespace Constant{ 
    static const unsigned int framerate = 60; 
    static const char * const windowName = "Test"; 
    static const unsigned char * const cursorBitmap = { lots of data }; 
} 

lubię tego formatu, ponieważ pozwala mi zachować moje stałe w jednym miejscu, i unika konieczności zadeklarować stałą w jednym pliku i zdefiniować go w innym, pomagając czytelności. Gdy jednak jednostka tłumaczeniowa zawiera constants.h, rozszerza te definicje na miejsce, na jednostkę.

Moje pytanie brzmi, czy spowoduje to znaczny wzrost kosztów, jeśli włączyłem constants.h do wielu jednostek tłumaczeniowych i na przykład cursorBitmap, a inne stałe tablicowe są znacznie większe? Czy mój program będzie zawierał 100 kopii każdego ciągu liter i liter, jeśli uwzględnię go w 100 jednostkach? Czy skopiowane zostaną tylko wskaźniki i wartości?

Jeśli jest narzut, czy jest sposób, w jaki mogę tego uniknąć, bez potrzeby oddzielania deklaracji i definicji?

(też jestem zgadywania „statyczne” jest zbędne w tym użytkowania, ale chciałbym umieścić go tam i tak)

+2

Co więcej, szkic C++ 17 ma zmienne 'inline'. – Simple

+0

To robi ** nie **, unikając konieczności definiowania tych zmiennych w innym pliku. Są to deklaracje iw wielu przypadkach nie trzeba podawać definicji, ale w niektórych przypadkach nie. Na przykład, jeśli przekażesz jedną z tych stałych do funkcji, która przyjmuje ją przez odniesienie, będziesz potrzebować definicji. –

Odpowiedz

3

czy literały łańcuchowe są powielane w różnych jednostkach translacji jest jakość błąd implementacji.

Bezpośrednio zadeklarowane obiekty zostaną zduplikowane w każdej jednostce tłumaczeniowej, w której znajduje się ten nagłówek. To jednak nie jest dużo. W jednostce tłumaczeniowej, w której adres stałej nie jest bezpośrednio lub pośrednio używany, można ją zoptymalizować.

Jeśli chcesz mieć pewność, tylko jedna kopia każdej stałej, lub nawet bez kopii, a następnie można użyć szablonu klasy, podobnie jak to:

constants.h
#pragma once 

template< class Dummy > 
struct Constant_{ 
    static const unsigned int framerate; 
    static const char * const windowName; 
    static const unsigned char * const cursorBitmap; 
}; 

template< class Dummy > 
const unsigned int Constant_<Dummy>::framerate = 60; 

template< class Dummy > 
const char * const Constant_<Dummy::windowName = "Test"; 

template< class Dummy > 
const unsigned char * const Constant_<Dummy>::cursorBitmap = ...; 

using Constant = Constant_<void>; 

Ale IMHO więcej pracować, niż to jest warte. Można również użyć funkcji inline, po jednej dla każdej stałej.

+0

W jaki sposób TU są powiązane z ostatecznym połączonym plikiem binarnym? "Czy mój program będzie zawierał 100 kopii każdego ciągu liter i liter, jeśli uwzględnię go w 100 jednostkach?" A co z przypadkiem niestatycznych elementów? – xaxxon

+0

@xaxxon: Biblioteka i program to dwa różne rodzaje rzeczy. To pytanie dotyczy programu. Zwykła biblioteka to zbiór (przetłumaczonych) jednostek tłumaczeniowych, które mogą być używane pojedynczo lub masowo. Trudno jest wymyślić sposób uniknięcia duplikacji, ale nadal jest to problem z jakością implementacji. –

+0

@xaxxon: w odniesieniu do "nie-statyki", prawdopodobnie masz na myśli powiązanie zewnętrzne.Powyższa technika szablonów generuje stałe połączenia zewnętrzne, kompatybilne z modułami tylko nagłówkowymi. Alternatywą jest zdefiniowanie stałych w pliku implementacji, ale OP stwierdził, że chce tego uniknąć, "unika konieczności deklarowania stałej w jednym pliku i definiowania go w innym". –

0

pierwsze, stosując static w przestrzeni nazw jest przestarzała ponieważ C++ 98:

D.2 static kluczowego
Zastosowanie static kluczowych jest przestarzała podczas deklarowania obiektów w zakresie przestrzeni nazw (patrz 3.3 .5)

Po drugie, const oznacza wewnętrzne powiązanie w C++ przez siebie.

Po trzecie, dokładna odpowiedź zależy od kompilatora i używanych opcji. Duplikaty mogą zostać wyeliminowane przez kompilator/linker, szczególnie jeśli można użyć LTO (Link Time Optimization).

1

Czy mój program będzie zawierał 100 kopii każdego ciągu liter i liter, jeśli uwzględnię go w 100 jednostkach? Czy skopiowane zostaną tylko wskaźniki i wartości?

Standard nie obiecuje konsolidacji literałów ciągów, więc to zależy od implementacji.Prosty test wykorzystujący GCC 5.1.1 na GNU/Linux pokazał, że literały łańcuchowe są nie skonsolidowane w niezoptymalizowanej kompilacji, ale są konsolidowane, gdy jest używany. Ale to tylko połączenie rzeczywistych tablic char. W zakresie, w którym kompilator nie optymalizuje pamięci dla wskaźnika lub stałych numerycznych (jeśli są one lokalne dla jednostki tłumaczeniowej, a nie dla ODR i typu POD, są oczywistymi kandydatami do eliminacji w ramach as-if), jednak kompilator może nie być w stanie ich łatwo skonsolidować. Standard wymaga, aby były różnymi obiektami i dlatego muszą mieć różne adresy. Reguła as-if może nadal zezwalać na ich usunięcie, nawet jeśli masz wziąć ich adresy, ale generalnie wymagałoby to optymalizacji globalnego programu, np. Optymalizacji czasu łącza, w tym bibliotek, których implementacja może nie obsługiwać, obsługiwać tylko w ograniczonym zakresie i/lub tylko w zależności od ustawień kompilatora i linkera. Innymi słowy, może się to zdarzyć w odpowiednich okolicznościach, ale jest o wiele bardziej prawdopodobne, że tak się nie stanie.

Moje własne badania wskazują, że GCC 5.1.1 nie konsoliduje static const unsigned int przedmioty wystawione przez const ref, nawet z -Os -flto (optymalizacja pod kątem wielkości i umożliwiają optymalizację link-time). Szczerze mówiąc, byłbym zaskoczony, gdyby jakakolwiek współczesna implementacja wykonała tę trudną i niejasną optymalizację.

(też jestem zgadywania „statyczne” jest zbędne w tym użytkowania, ale chciałbym umieścić go tam i tak)

To nie jest zbędny, jeśli masz wiele jednostek tłumaczeniowych, ponieważ w przeciwnym razie przebiegają wbrew zasadzie jednej definicji (ODR). Na marginesie jednak, static w zakresie przestrzeni nazw było przez długi czas uważane za składnie przestarzałe (zamiast tego należy rozważyć użycie anonimowych przestrzeni nazw wprowadzonych w C++ 98).

(. W odpowiedzi na okrzyki i HTH - Alf)

Jeśli chcesz mieć pewność, tylko jedna kopia każdej stałej, lub nawet bez kopii, a następnie można użyć szablonu klasy, podobnie jak to:

Nie ma szczęścia. W standardzie nie ma gwarancji, ile miejsca zajmuje szablon. Cały szablon gwarantuje, że tylko jedna z potencjalnie wielu kopii jest używana - lub wydaje się być używana - zgodnie z zasadą "jak to". W rzeczywistości jest to gorsze, ponieważ przynajmniej GCC 5.1.1 w rzeczywistości nie nie usunąć nadmiarowy static const unsigned int nawet z -Os -flto w moim systemie. Oznacza to, że w przypadku dwóch jednostek tłumaczeniowych wartość inicjalizatora dla unsigned int można znaleźć w dwóch oddzielnych lokalizacjach, mimo że używana jest tylko jedna z nich (wszystkie wskaźniki i odniesienia odnoszą się tylko do tej lokalizacji).