Czy zmienne globalne są złe? [Zamknięte]


247

Czy w C / C ++ zmienne globalne są tak złe, jak myśli mój profesor?


17
Ugryzę się na wypadek, gdyby próbował powiedzieć żart ... „jak bardzo są źli”?
Zach Scrivena

13
Myślę, że to pytanie było całkiem interesujące! Rozwój oprogramowania wciąż stoi w obliczu tych samych starych pułapek od samego początku, a programiści często nie wiedzą, że używanie zmiennych globalnych, gotos, zmiennych o krótkich nazwach NIE JEST problemem. Niepoprawny kod jest zapisywany codziennie bez ich używania. +1
Sylvain Rodrigue

69
Jak możemy odpowiedzieć? Nie powiedział nam, jak źle myśli jego profesor. :)
Steve Fallows

9
@Juan Mendes I 100% zgadzam się z tobą! Problem, o którym mówiłem, polega na tym, że wielu programistów wie, że nie powinni używać zmiennych globalnych, ale po prostu NIE wiedzą, dlaczego! I tak widziałem wiele dużych programów, w których każda funkcja otrzymała tę samą mega-strukturę zawierającą +100 pól - Spójrz mamo, żadnych zmiennych globalnych! Ten sam problem, co tak zwane „dobre praktyki”: są to dobre praktyki w NIEKTÓRYCH kontekstach, a nie we wszystkich kontekstach. Używając ich, MOŻESZ utworzyć niemożliwy do utrzymania kod. Twoje zdrowie.
Sylvain Rodrigue

3
Istnieje niewiele dobrych zastosowań zmiennych globalnych. Jednym z możliwych, ale dyskusyjnych zastosowań, byłby globalny obiekt „konfiguracyjny”, który wczytuje plik konfiguracyjny raz podczas uruchamiania.
Siler

Odpowiedzi:


257

Problem ze zmiennymi globalnymi polega na tym, że ponieważ każda funkcja ma do nich dostęp, coraz trudniej jest ustalić, które funkcje faktycznie odczytują i zapisują te zmienne.

Aby zrozumieć, jak działa aplikacja, musisz wziąć pod uwagę każdą funkcję, która modyfikuje stan globalny. Można to zrobić, ale wraz z rozwojem aplikacji będzie ona trudniejsza do tego stopnia, że ​​będzie praktycznie niemożliwa (lub przynajmniej kompletna strata czasu).

Jeśli nie korzystasz ze zmiennych globalnych, możesz przekazać stan pomiędzy różnymi funkcjami w razie potrzeby. W ten sposób masz znacznie większą szansę na zrozumienie, co robi każda funkcja, ponieważ nie musisz brać pod uwagę stanu globalnego.


10
Ta odpowiedź jest naprawdę dobra. Połącz to z odpowiedzią „zminimalizuj zmienny zakres” stackoverflow.com/questions/357187/…
bobobobo

17
Zastąp „klasę” terminem „aplikacja” i „stan obiektu” zamiast „stan globalny”, a ty podasz dokładnie ten sam argument za niestosowaniu zmiennych składowych (pól) w klasach. Prawdziwą odpowiedzią jest użycie ich w razie potrzeby.
Ian Goldby

2
Kilka (być może głupich) pytań: 1) Jeśli chcesz wiedzieć, które funkcje odczytują i zapisują te zmienne, czy nie możesz po prostu użyć funkcji „znajdź” w edytorze, aby dostrzec przypadki modyfikacji wartości w tych zmiennych? 2) „Można tego dokonać ... kompletna strata czasu).” Czy możesz podać przykład? 3) „Jeśli nie polegasz na zmiennych globalnych, ... nie musisz brać pod uwagę stanu globalnego”. Nie rozumiem, jak to jest zaletą. Być może przydałby mi się taki przykład.
Andrei

2
@ bobobobo zepsuty link, czy możemy pobrać zrzut ekranu od ciebie, użytkownika 10k +?
noɥʇʎԀʎzɐɹƆ

3
@ noɥʇʎԀʎzɐɹƆ Proszę bardzo! i.imgur.com/RwRgJLZ.jpg
Mateen

85

Ważne jest, aby pamiętać o ogólnym celu: przejrzystości

Istnieje reguła „bez zmiennych globalnych”, ponieważ przez większość czasu zmienne globalne sprawiają, że znaczenie kodu jest mniej jasne.

Jednak, podobnie jak wiele reguł, ludzie pamiętają tę regułę, a nie jej przeznaczenie.

Widziałem programy, które wydają się podwoić rozmiar kodu, przekazując ogromną liczbę parametrów, aby uniknąć zła zmiennych globalnych. W końcu użycie globałów uczyniłoby program bardziej zrozumiałym dla osób go czytających. Bezmyślnie przestrzegając słowa reguły, oryginalny programista zawiódł zamiar reguły.

Tak, globały są często złe. Ale jeśli uważasz, że w końcu intencja programisty została wyjaśniona dzięki zastosowaniu zmiennych globalnych, to idź dalej. Pamiętaj jednak o spadku przejrzystości, który pojawia się automatycznie, gdy zmusisz kogoś do uzyskania dostępu do drugiego fragmentu kodu (globali), aby zrozumieć, jak działa ten pierwszy fragment.


8
Sugerowanie używania zmiennych globalnych zamiast przekazywania jest receptą na to, że Twój kod nie nadaje się do ponownego użycia i jest niebezpieczny dla wielowątkowości
Juan Mendes

16
Sugerowanie globalizacji w odpowiednich okolicznościach to przepis na bardziej przejrzysty i wydajniejszy kod. „Przekazywanie” wymaga stałego dynamicznego przydzielania pamięci stosu, a byłoby to głupie dla czegoś, co powinno być globalne, takie jak globalny bufor dla przychodzących danych gniazda. Na przykład, jeśli masz funkcję odczytującą Winsock recv (), dlaczego ciągle tworzysz i zwalniasz ten bufor w ramach każdego wywołania? Zmień bufor na globalny. Wiele wątków i tak go nie czyta.
James

Ciekawe, jaki program podwaja rozmiar kodu, przekazując parametry, aby uniknąć zmiennych globalnych? Z mojego doświadczenia wynika, że ​​używanie zmiennych globalnych może rozwiązać problemy z ujawnieniem danych, ale zwykle istnieje dodatkowa złożona logika, którą należy dodać, aby upewnić się, że te magiczne zmienne zachowują się poprawnie.
user2167582

3
Jeśli ktoś przekazuje około 100 zmiennych, to nie nauczył się, czym jest obiekt. Korzystanie z odniesienia do tego obiektu w najgorszym przypadku polega na przekazywaniu wskaźnika. Powiedziałbym, że reguła nie jest tylko jasnością, ale także testowalnością - a użycie nieglobalnego świata znacznie ułatwia testowanie.
UKMonkey,

2
„Jeśli ktoś przekazuje około 100 zmiennych, to nie nauczył się, czym jest obiekt”. Zgadzam się, ale nie cały świat jest zorientowany obiektowo. Moim osobistym przykładem podwojenia rozmiaru kodu był duży program Fortran, około 1986 roku. Jako nowy pracownik uniwersytetu „poprawiłem” go, dodając około 30 parametrów do każdego połączenia, eliminując wszystkie globale. Potem cofnąłem moją poprawę, gdy zdałem sobie sprawę z tego, co dokonałem.
Tom West

64

Mój profesor zwykł mówić coś w stylu: używanie zmiennych globalnych jest w porządku, jeśli używasz ich poprawnie. Nie sądzę, żebym kiedykolwiek dobrze je używał, więc rzadko ich używałem.


25
Tak prawdziwe. Są jak gotos, jeśli nie wiesz, kiedy ich użyć, nigdy tego nie rób.
David Holm

5
W mojej obecnej firmie często używają staticzmiennych globalnych, językiem jest C. Ponieważ są ograniczone do stosunkowo małych jednostek tłumaczeniowych, zaczynają przypominać zmienne klasowe obiektów C ++.
Vorac

1
@ Zmienne statyczne @Vorac nie są zmiennymi globalnymi, są zmiennymi lokalnymi. Zmienna globalna jest zmienną dostępną wszędzie w programie (stąd „global”, duh). Nie należy mylić ze zmiennymi zakresu pliku , które są zmiennymi zadeklarowanymi poza jakąkolwiek funkcją. Zmienna zakresu pliku statycznego nie jest zmienną globalną.
Lundin

1
Aby poprawić sobie, program lifetime, file scope variables. I stają się dość globalne, gdy przekażesz wskaźnik do zmiennej światu zewnętrznemu (co jest niemożliwe w przypadku zmiennych automatycznych).
Vorac

@Lundin Zgadzam się, staticzmienne globalne mają ograniczony zakres do tej samej jednostki tłumaczeniowej. Ale mają żywotność do końca programu jako dowolną zmienną globalną.
akhilesh1988,

38

Zmiennych globalnych należy używać tylko wtedy, gdy nie ma alternatywy. I tak, obejmuje Singletony. W 90% przypadków zmienne globalne są wprowadzane w celu zaoszczędzenia kosztów związanych z pomijaniem parametru. A potem dzieje się wielowątkowość / testowanie jednostkowe / kodowanie konserwacyjne i masz problem.

Tak, w 90% przypadków zmienne globalne są złe. Wyjątki prawdopodobnie nie będą widoczne w latach studiów. Jedyny wyjątek, który mogę oderwać od głowy, dotyczy z natury globalnych obiektów, takich jak tabele przerwań. Rzeczy takie jak połączenie DB wydają się być globalne, ale nie są.


2
Jedynym wyjątkiem, że ja piła w moich lat studenckich był funkcje graficzne call-back. W XWindows wywołania zwrotne myszy nie miały nieważnych * argumentów danych, które pozwalały na przekazywanie dowolnych fragmentów stanu programu ... (nie to, że i tak jest DUŻO lepszy niż globalny ...)
Brian Postow,

10
+1 dla „Rzeczy takie jak połączenie DB wydają się globalne, ale nie są”.
R .. GitHub ZATRZYMAJ LÓD

1
Tabele przerwań nie są globalne, jest jedna na procesor - ale jest też jedna instancja programu na procesor, więc „anuluje”.
user253751

1
Czy ktoś może mi wyjaśnić, dlaczego połączenia DB nie są globalne (i co byłoby dobrą alternatywą)? Zawsze myślałem o związkach jako o jednym z rzadkich przypadków, w których globały były akceptowalne.
Floella

33

Problem, który tworzą zmienne globalne dla programisty, polega na tym, że rozszerza on powierzchnię sprzęgania między komponentami między różnymi komponentami używającymi zmiennych globalnych. Oznacza to, że wraz ze wzrostem liczby składników wykorzystujących zmienną globalną może również wzrosnąć złożoność interakcji. To zwiększone sprzężenie zwykle ułatwia wprowadzanie defektów do systemu podczas wprowadzania zmian, a także utrudnia diagnozowanie i poprawianie defektów. To zwiększenie sprzężenia może również zmniejszyć liczbę dostępnych opcji podczas wprowadzania zmian i może zwiększyć wysiłek wymagany do wprowadzenia zmian, ponieważ często należy prześledzić różne moduły, które również używają zmiennej globalnej w celu ustalenia konsekwencji zmian.

Celem enkapsulacji , która jest w zasadzie przeciwieństwem stosowania zmiennych globalnych, jest zmniejszenie sprzężenia, aby łatwiej i bezpieczniej zrozumieć i zmienić źródło. Testy jednostkowe są znacznie łatwiejsze, gdy nie są używane zmienne globalne.

Na przykład jeśli masz prostą globalną zmienną całkowitą, która jest używana jako wyliczony wskaźnik, który różne komponenty wykorzystują jako maszynę stanu, a następnie dokonujesz zmiany poprzez dodanie nowego stanu dla nowego komponentu, musisz prześledzić wszystkie pozostałe składniki, aby zapewnić, że zmiana nie wpłynie na nie. Przykładem potencjalnego problemu może być użycie switchinstrukcji do testowania wartości zmiennej globalnej wyliczenia z caseinstrukcjami dla każdej z bieżących wartości w różnych miejscach i zdarza się, że niektóre switchinstrukcje nie mają defaultprzypadku do obsłużenia nieoczekiwana wartość dla globalnego nagle masz niezdefiniowane zachowanie w odniesieniu do aplikacji.

Z drugiej strony użycie współdzielonego obszaru danych może być wykorzystane do przechowywania zestawu parametrów globalnych, do których odwołuje się aplikacja. Takie podejście jest często stosowane w aplikacjach osadzonych z małą ilością pamięci.

Podczas korzystania ze zmiennych globalnych w tego rodzaju aplikacjach zazwyczaj odpowiedzialność za zapis w obszarze danych jest przypisana do pojedynczego komponentu, a wszystkie pozostałe komponenty widzą ten obszar jako consti odczytują go, nigdy do niego nie pisząc. Takie podejście ogranicza problemy, które mogą się rozwinąć.

Kilka problemów ze zmiennymi globalnymi, które należy rozwiązać

Gdy źródło zmiennej globalnej, takiej jak struct, zostanie zmodyfikowane, wszystko, co go używa, musi zostać ponownie skompilowane, aby wszystko, co korzysta ze zmiennej, znało jej prawdziwy rozmiar i szablon pamięci.

Jeśli więcej niż jeden składnik może modyfikować zmienną globalną, możesz napotkać problemy z niespójnością danych znajdujących się w zmiennej globalnej. W przypadku aplikacji wielowątkowej prawdopodobnie będziesz musiał dodać jakiś region blokujący lub krytyczny, aby zapewnić sposób, że tylko jeden wątek może modyfikować zmienną globalną na raz, a gdy wątek modyfikuje zmienną, wszystkie zmiany są zakończone i zatwierdzone, zanim inne wątki będą mogły zapytać o zmienną lub ją zmodyfikować.

Debugowanie aplikacji wielowątkowej, która korzysta ze zmiennej globalnej, może być trudniejsze. Możesz spotkać się z warunkami wyścigu, które mogą powodować wady, które są trudne do odtworzenia. Z kilkoma komponentami komunikującymi się za pośrednictwem zmiennej globalnej, szczególnie w aplikacji wielowątkowej, wiedza o tym, który komponent zmienia zmienną, kiedy i jak ją zmienia, może być bardzo trudna do zrozumienia.

Zderzenie nazw może być problemem przy stosowaniu zmiennych globalnych. Zmienna lokalna o takiej samej nazwie jak zmienna globalna może ukryć zmienną globalną. Podczas korzystania z języka programowania C można również natknąć się na problem konwencji nazewnictwa. Obejściem tego problemu jest podzielenie systemu na podsystemy ze zmiennymi globalnymi dla konkretnego podsystemu, zaczynając od tych samych pierwszych trzech liter (zobacz to na temat rozwiązywania kolizji przestrzeni nazw w celu C ). C ++ zapewnia przestrzenie nazw, a za pomocą C można obejść ten problem, tworząc globalnie widoczną strukturę, której członkami są różne elementy danych i wskaźniki do danych i funkcji, które są dostarczane w pliku jako statyczne, a więc z widocznością pliku, dzięki czemu można się do nich odwoływać tylko poprzez globalnie widoczna struktura.

W niektórych przypadkach pierwotne zamiary aplikacji są zmieniane, tak że zmienne globalne określające stan pojedynczego wątku są modyfikowane, aby umożliwić działanie kilku duplikatów wątków. Przykładem może być prosta aplikacja przeznaczona dla pojedynczego użytkownika korzystająca ze zmiennych globalnych dla stanu, a następnie zarząd przychodzi z prośbą o dodanie interfejsu REST, aby umożliwić zdalnym aplikacjom działanie jako użytkownicy wirtualni. Więc teraz musisz zduplikować zmienne globalne i ich informacje o stanie, aby pojedynczy użytkownik, a także każdy użytkownik wirtualny ze zdalnych aplikacji, mieli swój własny, unikalny zestaw zmiennych globalnych.

Korzystanie z C ++ namespacei structtechniki dla C.

Dla języka programowania C ++ namespacedyrektywa stanowi ogromną pomoc w zmniejszeniu szansy na konflikt nazw. namespacewraz z classróżnymi słowami kluczowymi dostępu ( private, protectedi public) zapewniają większość narzędzi potrzebnych do enkapsulacji zmiennych. Jednak język programowania C nie zapewnia tej dyrektywy. To księgowanie przepełnienia stosu , Przestrzenie nazw w C , zapewnia pewne techniki dla C.

Przydatną techniką jest posiadanie pojedynczego obszaru danych rezydującego w pamięci, który jest zdefiniowany jako taki, structktóry ma globalną widoczność i w tym structsą wskaźniki różnych zmiennych globalnych i funkcji, które są ujawniane. Rzeczywiste definicje zmiennych globalnych podano w zakresie pliku za pomocą staticsłowa kluczowego. Jeśli następnie użyjesz tego constsłowa kluczowego, aby wskazać, które są tylko do odczytu, kompilator może pomóc Ci wymusić dostęp tylko do odczytu.

Korzystanie z tej structtechniki może również obejmować globalność, dzięki czemu staje się ona rodzajem pakietu lub komponentu, który okazuje się globalny. Dzięki temu komponentowi łatwiej jest zarządzać zmianami, które wpływają na globalność i funkcjonalność za pomocą globalnej.

Jednak podczas namespacelub structtechnika może pomóc zarządzać nazwy starć, podstawowe problemy sprzężenia między składnika których stosowanie globalnych wprowadza w szczególności w nowoczesnych aplikacji wielowątkowym nadal istnieją.


Jest to najlepsza egzaplanacja, która wyjaśnia wszystko. Sława!
johndoevodka

Twój język powinien mieć regułę kodową, która powstrzyma cię od używania zbyt dużej ilości sprzężeń klas.
Melbourne Developer

19

Tak, ale nie ponosisz kosztu zmiennych globalnych, dopóki nie przestaniesz pracować w kodzie, który używa zmiennych globalnych i nie zaczniesz pisać czegoś innego, który używa kodu, który używa zmiennych globalnych. Ale koszty wciąż tam są.

Innymi słowy, jest to długoterminowy koszt pośredni i jako taki większość ludzi uważa, że ​​nie jest źle.


19

Jeśli to możliwe, twój kod zostanie poddany intensywnej analizie podczas procesu w Sądzie Najwyższym , to musisz unikać zmiennych globalnych.

Zobacz ten artykuł: Kod alkomatu Buggy odzwierciedla znaczenie przeglądu źródła

Wystąpiły pewne problemy ze stylem kodu, które zostały zidentyfikowane w obu badaniach. Jednym z problemów stylistycznych, które dotyczyły recenzentów, było szerokie stosowanie niezabezpieczonych zmiennych globalnych . Jest to uważane za kiepską formę, ponieważ zwiększa ryzyko, że stan programu stanie się niespójny lub że wartości zostaną przypadkowo zmodyfikowane lub nadpisane. Badacze wyrazili również pewne obawy dotyczące faktu, że precyzja dziesiętna nie jest utrzymywana konsekwentnie w całym kodzie.

Założę się, że ci programiści żałują, że nie użyli zmiennych globalnych!


6
To był najlepszy śmiech, jaki kiedykolwiek miałem. Prawdziwy przykład tego, dlaczego rozwój zamkniętego źródła dla zysku jest zły, a dobry przykład globalnych zmienności poszedł nie tak!
Evil Spork,

Ustalono tutaj, że zmienne globalne są postrzegane z pogardą. Nic tu nie pokazuje, że zmienne globalne były prawdziwym problemem w kodzie. SysTest powiedział, że chociaż kod „nie został napisany w sposób zgodny ze zwykłymi najlepszymi praktykami projektowania oprogramowania”, to nadal „niezawodnie zapewniałby spójne wyniki testów”. Tak więc nie udokumentowano żadnej szkody ze strony globaliów. Moim zdaniem, właśnie ustalili, że: „Cóż, ci deweloperzy nie praktykują tej samej religii kodowania, co reszta głównego nurtu świata”.
LionKimbro,

19

Zmienne globalne są tak złe, jak je tworzysz, nie mniej.

Jeśli tworzysz w pełni zamknięty program, możesz używać globałów. Używanie globałów jest „grzechem”, ale grzechy programowania są mało filozoficzne.

Jeśli sprawdzisz L.in.oleum , zobaczysz język, którego zmienne są wyłącznie globalne. Jest to nieskalowalne, ponieważ wszystkie biblioteki nie mają innego wyboru, jak używać globałów.

To powiedziawszy, jeśli masz wybór i możesz zignorować filozofię programisty, globale nie są wcale takie złe.

Nie są też Gotos, jeśli dobrze je wykorzystasz.

Dużym „złym” problemem jest to, że jeśli użyjesz ich źle, ludzie krzyczą, lądownik marsjański rozbije się, a świat wysadzi… lub coś w tym rodzaju.


17
Lekceważenie problemów związanych z używaniem globali dla zdezorientowanego studenta nie jest dobrym pomysłem IMO.
GEOCHET

3
Filozofia projektowania nie jest obiektywna. Bynajmniej. To, że większość programistów czegoś nie lubi, nie oznacza, że ​​nigdy nie należy na to patrzeć. Łatwo jest korzystać z globałów bez końca świata. Pozwól mu to zrobić, walcz (wiedząc, że to zrobi) i naucz się, jak to zrobić.
user54650

7
Rich ma rację. Ta odpowiedź nie mówi nic o tym, co jest / nie jest złe (ani o tym, jak bezpiecznie używać globałów), tylko że „nie są tak złe jak wszystko. Jako takie, tylko bagatelizuje problemy.
jalf

4
Nie zgadzam się, że zmienne globalne są tylko tak „złe, jak je czynisz”. Myślę, że jednym z głównych problemów, szczególnie w tym wielo-programistycznym, połączonym świecie, w którym większość z nas mieszka, pracuje i programuje, jest to, że zmienne globalne dają komuś ELSE szansę na pogorszenie kodu.
gariepy 8.04.16

@gariepy, dopóki się nie dowiem, że rozmowa dotyczy statystyki: D OK, więc to jest to ... a moja aplikacja ma tylko jedną lub dwie zmienne globalne, to jest jedna z Visual Studio, DEBUG i TRACE, których normalnie nie używamy: D
deadManN

17

Odpowiedziałbym na to pytanie innym pytaniem: Czy używasz pojedynczych przycisków / Czy pojedyncze przyciski są złe?

Ponieważ (prawie wszystkie) użycie singeltonów jest uwielbioną zmienną globalną.


11
Już miałem zamieścić mądry komentarz, mówiąc: „Są złe tylko wtedy, gdy nazwiesz je globalsami zamiast singletonami”, ale pobiłeś mnie do tego.
smo

Wciąż próbuję dowiedzieć się, czym są LOL singletony.
GeoffreyF67

1
@Geoffrey: oto kilka dobrych opisów SO - stackoverflow.com/questions/11831/... oraz kilka dobrych linków: stackoverflow.com/questions/11831/…
Gavin Miller

10
Dla przypomnienia, singleton jest zmienną globalną o uwielbianej nazwie Design Patterns (tm) (lol), aby brzmiała ona poprawnie. Jest równie zły z tych samych powodów.
R .. GitHub ZATRZYMAJ LÓD

@GavinMiller Mówią, że jest w porządku, jeśli używasz simpleton ... ooops, singleton eufemizm?
Juan Mendes

14

Problemem jest to, że są złe , a bardziej, że są niebezpieczne . Mają własny zestaw zalet i wad, a są sytuacje, w których są albo najbardziej wydajni, albo jedyny sposób na osiągnięcie określonego zadania. Jednak są bardzo łatwe do niewłaściwego użycia, nawet jeśli podejmiesz kroki, aby zawsze używać ich prawidłowo.

Kilka zalet:

  • Można uzyskać do niego dostęp z dowolnej funkcji.
  • Można uzyskać dostęp z wielu wątków.
  • Nigdy nie wyjdzie poza zakres, dopóki program się nie zakończy.

Kilka wad:

  • Można uzyskać do niego dostęp z dowolnej funkcji, bez potrzeby jawnego przeciągania go jako parametru i / lub dokumentowania.
  • Nie jest bezpieczny dla wątków.
  • Zanieczyszcza globalną przestrzeń nazw i potencjalnie powoduje kolizje nazw, chyba że zostaną podjęte odpowiednie środki, aby temu zapobiec.

Zauważ, że jeśli chcesz, pierwsze dwa plusy i dwa pierwsze minusy, które wymieniłem, są dokładnie takie same, tylko z innym brzmieniem. Jest tak, ponieważ cechy zmiennej globalnej mogą być rzeczywiście przydatne, ale same cechy, które czynią je użytecznymi, są źródłem wszystkich ich problemów.

Kilka potencjalnych rozwiązań niektórych problemów:

  • Zastanów się, czy to rzeczywiście najlepsze lub najskuteczniejsze rozwiązanie problemu. Jeśli są jakieś lepsze rozwiązania, skorzystaj z nich zamiast tego.
  • Umieść je w przestrzeni nazw [C ++] lub singleton struct [C, C ++] z unikalną nazwą (dobrym przykładem byłoby Globalslub GlobalVars) lub użyj standardowej konwencji nazewnictwa dla zmiennych globalnych (takich jak global_[name]lub g_module_varNameStyle(jak wspomniano w underscore_d w komentarzach )). Spowoduje to zarówno udokumentowanie ich użycia (można znaleźć kod, który korzysta ze zmiennych globalnych, wyszukując przestrzeń nazw / nazwę struktury), jak i zminimalizować wpływ na globalną przestrzeń nazw.
  • Dla każdej funkcji, która uzyskuje dostęp do zmiennych globalnych, wyraźnie udokumentuj, które zmienne odczytuje i które zapisuje. Ułatwi to rozwiązywanie problemów.
  • Umieść je we własnym pliku źródłowym i zadeklaruj externw powiązanym nagłówku, aby ich użycie mogło być ograniczone do jednostek kompilacji, które potrzebują do nich dostępu. Jeśli Twój kod opiera się na wielu zmiennych globalnych, ale każda jednostka kompilacji potrzebuje tylko dostępu do kilku z nich, możesz rozważyć posortowanie ich w wielu plikach źródłowych, dzięki czemu łatwiej jest ograniczyć dostęp każdego pliku do zmiennych globalnych.
  • Skonfiguruj mechanizm blokowania i odblokowywania ich i / lub zaprojektuj swój kod, tak aby jak najmniej funkcji mogło faktycznie modyfikować zmienne globalne. Czytanie ich jest o wiele bezpieczniejsze niż pisanie, chociaż wyścigi wątków mogą nadal powodować problemy w programach wielowątkowych.
  • Zasadniczo zminimalizuj dostęp do nich i zmaksymalizuj unikalność nazw. Chcesz uniknąć kolizji nazw i mieć jak najmniej funkcji, które mogą potencjalnie modyfikować dowolną zmienną.

To, czy są dobre, czy złe, zależy od tego, jak z nich korzystasz. Większość z nich źle je wykorzystuje, stąd ogólna ostrożność wobec nich. Przy właściwym stosowaniu mogą być dużym dobrodziejstwem; jeśli źle wykorzystane, jednak mogą i będą wracać gryźć jak i kiedy najmniej się tego spodziewasz.

Dobrym sposobem na to jest to, że sami nie są źli, ale umożliwiają zły projekt i mogą wykładniczo zwielokrotniać skutki złego projektu.


Nawet jeśli nie zamierzasz ich używać, lepiej wiedzieć, jak ich używać bezpiecznie i zdecydować, że nie, niż nie używać ich, ponieważ nie wiesz, jak bezpiecznie z nich korzystać. Jeśli kiedykolwiek znajdziesz się w sytuacji, w której musisz zachować wcześniej istniejący kod, który opiera się na zmiennych globalnych, możesz mieć trudności, jeśli nie wiesz, jak prawidłowo z nich korzystać.


1
+1 za pragmatyzm. Singleton często po prostu dodaje płytę kotłową, aby przekształcić instancję i refaktor w członków, i w efekcie powstają ... zmienne globalne, po prostu maskarujące się pod inną nazwą. Po co zawracać sobie głowę, oprócz unikania Grzechu Globalnego jedynie ze względów technicznych? Przestrzenie nazw są fajne jako bariera, ale uważam, że proste jest g_module_varNameStyledoskonale czytelne. Żeby było jasne, nie używam globalnych, czy mogę go łatwo uniknąć - słowo kluczowe łatwo , bo odkąd przestał muszą być unikane wierzyć - albo raczej ukrywane - za wszelką cenę, mam o wiele lepszy czas, i mój kod jest (szokujący!) zdecydowanie bardziej uporządkowany
podkreślenie_d

@underscore_d Ma to głównie na celu łatwiejsze rozróżnienie między zmiennymi globalnymi i lokalnymi, a także ułatwienie lokalizacji zmiennych globalnych podczas przeszukiwania kodu, aby uniknąć pomyłki co do tego, czy zmienna jest globalna czy lokalna / parametr / członek / etc .. Standardowa konwencja nazewnictwa taka jak twoja działa równie dobrze, o ile jest spójna. Dziękuję za edycję mojej odpowiedzi przy pomocy standardowej konwencji konwencji nazewnictwa.
Justin Time - Przywróć Monikę

1
„Dla dowolnej funkcji ... jawnie dokumentuj, które zmienne” - pamiętaj, że jest to relacja przechodnia. Jeśli funkcja A wywołuje funkcje B i C, to odczytuje i zapisuje zmienne zapisane przez oba (plus te bezpośrednio w swoim ciele)
Caleth

11

Jak ktoś powiedział (parafrazuję) w innym wątku: „Takie zasady nie powinny być łamane, dopóki nie w pełni zrozumiesz konsekwencje takiego postępowania”.

Są chwile, kiedy zmienne globalne są potrzebne lub przynajmniej bardzo pomocne (na przykład praca z oddzwanianiami zdefiniowanymi przez system). Z drugiej strony są one również bardzo niebezpieczne z wszystkich powodów, o których ci mówiono.

Istnieje wiele aspektów programowania, które prawdopodobnie należy pozostawić ekspertom. Czasami POTRZEBUJESZ bardzo ostrego noża. Ale nie możesz użyć jednego, dopóki nie będziesz gotowy ...


1
Zgadzam się, jeśli rozumiesz konsekwencje, możesz złamać zasady, ale jeśli często przyłapujesz się na robieniu czegoś, robisz coś złego
Juan Mendes

9

Zmienne globalne są ogólnie złe, szczególnie jeśli inne osoby pracują nad tym samym kodem i nie chcą spędzać 20 minut na szukaniu wszystkich miejsc, do których odwołuje się zmienna. Dodanie wątków, które modyfikują zmienne, wprowadza zupełnie nowy poziom problemów.

Stałe globalne w anonimowej przestrzeni nazw używanej w pojedynczej jednostce tłumaczeniowej są dobre i wszechobecne w profesjonalnych aplikacjach i bibliotekach. Ale jeśli dane są zmienne i / lub muszą być współużytkowane przez wiele JT, możesz je kapsułkować - jeśli nie ze względu na projekt, to ze względu na osobę debugującą lub pracującą z twoim kodem.


9

Używanie zmiennych globalnych przypomina trochę zamiatanie ziemi pod dywan. Jest to szybka naprawa i znacznie łatwiejsze w krótkim okresie niż uzyskanie pojemnika na kurz lub odkurzacza, aby go wyczyścić. Jeśli jednak później przesuniesz dywan, będziesz miał pod spodem wielki bałagan.


leniwa metafora pozbawiona kontekstu! = odpowiedź
podkreślenie_d

1
@underscore_d: Nie zgadzam się. To pytanie do dyskusji, mimo że nie jest oznaczone jako takie (prawdopodobnie ze względu na swój wiek), a zatem tego typu odpowiedzi są całkowicie poprawne i stanowi punkt, który odnosi się do pytania PO.
gariepy 8.04.16

7

Zmienne globalne są złe, jeśli pozwalają manipulować aspektami programu, które powinny być modyfikowane tylko lokalnie. W OOP globale często są sprzeczne z ideą enkapsulacji.


7

Myślę, że twój profesor próbuje powstrzymać zły nawyk, zanim jeszcze się zacznie.

Zmienne globalne mają swoje miejsce i jak wiele osób mówi, wiedząc, gdzie i kiedy ich używać, może być skomplikowane. Myślę więc, że zamiast wdawać się w sedno tego, dlaczego, jak, kiedy i gdzie zmiennych globalnych, profesor postanowił po prostu zakazać. Kto wie, może ich zakazać w przyszłości.


7

Absolutnie nie. Nadużywanie ich ... to źle.

Bezmyślne usuwanie ich ze względu na to jest ... bezmyślne. O ile nie znasz zalet i wad, najlepiej kieruj się jasno i postępuj zgodnie z tym, czego się nauczyłeś, ale nie ma nic pośredniego w przypadku zmiennych globalnych. Kiedy zrozumiesz zalety i wady, lepiej podejmij własną decyzję.


3
-1 Istnieje wiele powodów, dla których należy unikać zmiennych globalnych: największym dla mnie jest to, że ukryte zależności i globalność sprawiają, że testowanie kodu w dowolny przewidywalny sposób jest niezwykle trudne. Chyba że nie cenisz możliwości testowania kodu w sposób zautomatyzowany, sugerowałbym, że zmienne globalne spowodują jedynie ból. Poza tym w dobrze ustrukturyzowanym programie zawsze są alternatywy.
jkp

1
to, co mówisz, jest ogromną nadmierną generalizacją, staranne użycie stanu globalnego nie zapobiega automatycznym testom - w rzeczywistości prawie wszystkie aplikacje mają stan globalny, niezależnie od tego, czy jest on zawijany jako dynamicznie przydzielane instancje dobrze zamkniętych obiektów lub dane statyczne, które są całkowicie widoczne nie ma znaczenia koncepcyjnego, nadal istnieją zależności - chodzi tylko o to, jak są zakodowane.
jheriko

1
Dokładnie. Zasadniczo nie są one tak „złe”, ale „łatwe do złamania”. Jeśli wiesz, jak z nich korzystać, nie niszcząc niczego, i kiedy ich używać zamiast alternatywy, mogą być pomocne. W przeciwnym razie ... nie tak bardzo.
Justin Time - Przywróć Monikę

4

Zmienne globalne są dobre w małych programach, ale okropne, jeśli są używane w ten sam sposób w dużych programach.

Oznacza to, że możesz łatwo przyzwyczaić się do korzystania z nich podczas nauki. Przed tym twój profesor stara się cię chronić.

Kiedy będziesz bardziej doświadczony, łatwiej będzie nauczyć się, kiedy będą w porządku.


4

Nie, wcale nie są złe. Musisz przyjrzeć się kodowi (maszynowemu) wygenerowanemu przez kompilator, aby dokonać tego ustalenia, czasami znacznie gorsze jest użycie lokalnego niż globalnego. Zauważ też, że nałożenie zmiennej „statycznej” na zmienną lokalną zasadniczo czyni ją globalną (i stwarza inne brzydkie problemy, które rozwiązałby prawdziwy globalny). „lokalne globale” są szczególnie złe.

Globals daje również czystą kontrolę nad zużyciem pamięci, co jest znacznie trudniejsze w przypadku mieszkańców. Obecnie ma to znaczenie tylko w środowiskach osadzonych, w których pamięć jest dość ograniczona. Przed założeniem, że osadzony jest taki sam jak w innych środowiskach i założeniem, że zasady programowania są takie same we wszystkich obszarach, należy wiedzieć.

Dobrze, że kwestionujesz nauczane zasady, większość z nich nie jest z powodów, o których ci mówiono. Najważniejsza lekcja nie polega jednak na tym, że jest to zasada, którą należy nosić ze sobą na zawsze, ale jest to zasada wymagana, aby honorować, aby przejść tę klasę i iść naprzód. W życiu przekonasz się, że dla firmy XYZ będziesz mieć inne zasady programowania, które w końcu będziesz musiał uszanować, aby nadal otrzymywać wypłatę. W obu sytuacjach możesz podważyć zasadę, ale myślę, że będziesz miał dużo więcej szczęścia w pracy niż w szkole. Jesteś tylko jednym z wielu studentów, twoje miejsce zostanie wkrótce zastąpione, profesorowie tego nie zrobią, w pracy jesteś jednym z małego zespołu graczy, którzy muszą zobaczyć ten produkt do końca i w takim środowisku opracowane zasady dotyczą korzyści członków zespołu, a także produktu i firmy, więc jeśli wszyscy są podobnie nastawieni lub jeśli chodzi o konkretny produkt, istnieje dobry powód techniczny, aby naruszyć coś, czego nauczyłeś się na studiach lub książkę o programowaniu ogólnym, to sprzedaj swój pomysł zespołowi i zapisz go jako prawidłową, jeśli nie preferowaną metodę . W prawdziwym świecie wszystko jest uczciwe.

Jeśli będziesz przestrzegać wszystkich zasad programowania, których nauczyłeś się w szkole lub w książkach, twoja kariera programistyczna będzie bardzo ograniczona. Prawdopodobnie możesz przetrwać i mieć owocną karierę, ale szerokość i szerokość dostępnych dla ciebie środowisk będzie bardzo ograniczona. Jeśli wiesz, jak i dlaczego istnieje reguła i możesz ją obronić, to dobrze, jeśli tylko rozumujesz, ponieważ „tak powiedział mój nauczyciel”, to nie jest tak dobrze.

Zwróć uwagę, że takie tematy są często dyskutowane w miejscu pracy i tak będzie, ponieważ kompilatory i procesory (i języki) ewoluują, zmieniają się także takie zasady i bez obrony twojego stanowiska i być może nauczony przez kogoś z inną opinią, której nie chcesz pójść naprzód.

W międzyczasie, po prostu rób wszystko, co mówi najgłośniej lub mówi największy kij (do czasu, gdy będziesz krzyczał najgłośniej i niesie największy kij).


4
Czy to tylko inny sposób powiedzenia „nikt nigdy nie został zwolniony za zakup IBM”?
Gordon Potter,

1
Dobrze, że w przypadku niektórych aplikacji korzystających ze zmiennych globalnych może to ułatwić pracę. Zasadniczo używanie zmiennych globalnych jest źródłem problemów z ukrytymi ścieżkami sprzężenia między sekcjami źródła. Jednak posiadanie obszaru pamięci współdzielonej, który jest określany jako globalny, jest wykorzystywany w wielu implementacjach, takich jak interfejsy urządzeń lub być może globalna tabela parametrów zawierająca stałe różnych rodzajów lub tabelę skoków.
Richard Chambers

4

Chciałbym sprzeciwić się temu, aby w całym tym wątku było poruszone twierdzenie, że sprawia ono, że wielowątkowanie jest trudniejsze lub niemożliwe jako takie. Zmienne globalne są stanem wspólnym, ale alternatywy dla globałów (np. Przekazywanie wskaźników) mogą również współdzielić stan. Problem z wielowątkowością polega na tym, jak prawidłowo używać stanu współdzielonego, a nie czy stan ten jest współdzielony przez zmienną globalną, czy coś innego.

W większości przypadków, gdy robisz wielowątkowość, musisz coś udostępnić. Na przykład we wzorcu producent-konsument możesz udostępniać pewną bezpieczną dla wątków kolejkę, która zawiera jednostki robocze. Możesz je udostępniać, ponieważ ta struktura danych jest bezpieczna dla wątków. To, czy kolejka jest globalna, czy nie, jest całkowicie nieistotne, jeśli chodzi o bezpieczeństwo wątków.

Niejasna nadzieja wyrażona w tym wątku, że przekształcenie programu z jednowątkowego na wielowątkowy będzie łatwiejsza, gdy nie będzie używany globali, jest naiwna. Tak, globale ułatwiają strzelanie sobie w stopę, ale istnieje wiele sposobów na strzelanie sobie.

Nie opowiadam się za globalsami, ponieważ inne punkty nadal są ważne, mam na myśli tylko to, że liczba wątków w programie nie ma nic wspólnego ze zmiennym zakresem.


3

Tak, ponieważ jeśli pozwolisz, aby niekompetentni programiści z nich korzystali (czytaj 90%, szczególnie naukowcy), uzyskasz ponad 600 globalnych zmiennych rozłożonych na ponad 20 plików i projekt obejmujący 12 000 linii, w których 80% funkcji unieważnia, zwraca nieważność i działa całkowicie w stanie globalnym.

Szybko staje się niemożliwe do zrozumienia, co się dzieje w jednym punkcie, chyba że znasz cały projekt.


2

Zastosowanie zmiennych globalnych faktycznie zależy od wymagań. Jego zaletą jest to, że zmniejsza obciążenie związane z wielokrotnym przekazywaniem wartości.

Ale twój profesor ma rację, ponieważ rodzi to problemy z bezpieczeństwem, dlatego należy w jak największym stopniu unikać używania zmiennych globalnych. Zmienne globalne powodują również problemy, które czasami są trudne do debugowania .

Na przykład:-

Sytuacje, w których wartości zmiennych są modyfikowane w czasie wykonywania . W tej chwili trudno jest określić, która część kodu go modyfikuje i na jakich warunkach.


2

Globalne są dobre, jeśli chodzi o konfigurację . Kiedy chcemy, aby nasza konfiguracja / zmiany miały globalny wpływ na cały projekt .

Możemy więc zmienić jedną konfigurację, a zmiany są kierowane do całego projektu . Ale muszę ostrzec, że musisz być bardzo mądry, aby korzystać z globałów.


1

Wcześniej czy później będziesz musiał zmienić sposób ustawiania tej zmiennej lub co się stanie, gdy będzie ona dostępna, lub po prostu poluj tam, gdzie została zmieniona.

Praktycznie zawsze lepiej jest nie mieć zmiennych globalnych. Po prostu napisz tama, pobierz i ustaw metody i dławik, gdy będziesz ich potrzebować dzień, tydzień lub miesiąc później.


1

Zwykle używam globałów dla wartości, które rzadko są zmieniane, takie jak singletony lub wskaźniki funkcji, do funkcji w dynamicznie ładowanej bibliotece. Używanie zmiennych globalnych w aplikacjach wielowątkowych prowadzi zwykle do trudnego do śledzenia błędu, więc staram się tego unikać z reguły.

Używanie globalnego zamiast przekazywania argumentu jest często szybsze, ale jeśli piszesz aplikację wielowątkową, co często robisz w dzisiejszych czasach, zazwyczaj nie działa ona zbyt dobrze (możesz użyć statystyki wątków, ale wtedy wzrost wydajności jest wątpliwy) .


1

W aplikacjach internetowych w ramach Enterprize można używać do przechowywania danych specyficznych dla sesji / okna / wątku / użytkownika na serwerze w celu optymalizacji i do ochrony przed utratą pracy, gdy połączenie jest niestabilne. Jak wspomniano, warunki wyścigu muszą być spełnione. Używamy pojedynczej instancji klasy dla tych informacji i jest ona starannie zarządzana.


1

Ostatecznie Twój program lub aplikacja może nadal działać, ale musisz być uporządkowany i mieć pełne zrozumienie tego, co się dzieje. Jeśli podzielisz wartość zmiennej między wszystkie funkcje, może być trudno prześledzić, która funkcja zmienia wartość (jeśli funkcja to robi) i sprawia, że ​​debugowanie jest milion razy trudniejsze


0

bezpieczeństwo jest mniej oznacza, że ​​każdy może manipulować zmiennymi, jeśli są zadeklarowane jako globalne, aby wyjaśnić ten przykład, weź ten przykład, jeśli masz równowagę jako zmienną globalną w swoim programie bankowym, funkcja użytkownika może nią manipulować, podobnie jak urzędnik bankowy może również manipulować to jest problem. tylko użytkownik powinien mieć funkcję tylko do odczytu i wypłacania, ale urzędnik banku może dodać kwotę, gdy użytkownik osobiście przekazuje gotówkę na biurku. tak to działa


-1

W aplikacji wielowątkowej używaj zmiennych lokalnych zamiast zmiennych globalnych, aby uniknąć warunków wyścigu.

Warunek wyścigu występuje, gdy wiele wątków uzyskuje dostęp do współdzielonego zasobu, przy czym co najmniej jeden wątek ma dostęp do zapisu do danych. Następnie wynik programu nie jest przewidywalny i zależy od kolejności dostępu do danych przez różne wątki.

Więcej na ten temat tutaj, https://software.intel.com/en-us/articles/use-intel-parallel-inspector-to-find-race-conditions-in-openmp-based-multithreaded-code


W przypadku potomności: jest to co najmniej częściowo poprawne. W „zmiennych lokalnych” w tej odpowiedzi odnoszą się do wątku zmiennych -local, zamiast więcej wspólnych zmiennych zakresu lokalnego że PO ma na myśli. Skutki uboczne modyfikacji zmiennych globalnych w sposób niebezpieczny dla wątków są bardzo różne od skutków zmiany stanu globalnego w sposób niebieżny.
Jules
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.