Czy #pragma jest kiedyś częścią standardu C ++ 11?

140

Tradycyjnie, standardowym i przenośnym sposobem uniknięcia wielu włączeń nagłówków w C ++ było / jest użycie #ifndef - #define - #endifschematu dyrektyw prekompilatora, zwanego również schematem ochrony makr (zobacz fragment kodu poniżej).

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

Jednak w większości implementacji / kompilatorów (patrz rysunek poniżej) istnieje bardziej „elegancka” alternatywa, która służy temu samemu celowi, co schemat ochrony makro #pragma once. #pragma oncema kilka zalet w porównaniu ze schematem ochrony makr, w tym mniej kodu, unikanie kolizji nazw, a czasami poprawioną szybkość kompilacji.

wprowadź opis obrazu tutaj

Po przeprowadzeniu pewnych badań zdałem sobie sprawę, że chociaż #pragma oncedyrektywa jest obsługiwana przez prawie wszystkie znane kompilatory, istnieje niejasność dotycząca tego, czy #pragma oncedyrektywa jest częścią standardu C ++ 11, czy nie.

Pytania:

  • Czy ktoś mógłby wyjaśnić, czy #pragma oncedyrektywa jest częścią standardu C ++ 11, czy nie?
  • Jeśli nie jest częścią standardu C ++ 11, czy są jakieś plany włączenia go w późniejszych wersjach (np. C ++ 14 lub nowszych)?
  • Byłoby również miło, gdyby ktoś mógł bardziej szczegółowo omówić zalety / wady stosowania którejkolwiek z technik (tj. Makroostrożność kontra #pragma once).
101010
źródło
9
Nawiasem mówiąc, używanie podwójnych podkreśleń do osłon nagłówka jest zabronione przez normę, która zastrzega na implementację wszystkie symbole zaczynające się od podwójnego podkreślenia (oprócz innych).
Matteo Italia
9
Stosowanie początkowego podkreślenia, po którym następuje duża litera, jest również zabronione. Po drugie, gdzie jest zmętnienie? Widzę tylko obsługę kompilatora, nikt nie twierdzi, że jest to część standardu?
Yakk - Adam Nevraumont
1
Jeśli chodzi o trzeci punkt, spójrz na powiązane pytanie: Czy #pragma jest kiedyś bezpiecznym, obejmującym straż? Wystąpiła sytuacja, w której osłony głowy działają, ale #pragma oncezwykle nie.
user1942027
1
możliwy duplikat , ponieważ odpowiada na to pytanie bez wspominania o C ++ 11.
Yakk - Adam Nevraumont
3
Cóż, nie jest to zakodowane w żadnym oficjalnym dokumencie, ale można to uznać za de facto standard.
Siyuan Ren

Odpowiedzi:

107

#pragma oncenie jest standardem. Jest to szeroko rozpowszechnione (ale nie uniwersalne) rozszerzenie, z którego można korzystać

  • jeśli Twoje obawy dotyczące przenoszenia są ograniczone, i
  • możesz być pewien, że wszystkie pliki dołączane są zawsze na dysku lokalnym.

Był brany pod uwagę pod kątem normalizacji, ale odrzucony, ponieważ nie można go niezawodnie wdrożyć. (Problemy występują, gdy masz pliki dostępne przez kilka różnych zdalnych montowań).

Dość łatwo jest upewnić się, że nie ma konfliktów włączania zabezpieczeń w ramach jednego rozwoju. W przypadku bibliotek, które mogą być używane przez wiele różnych programów, oczywistym rozwiązaniem jest wygenerowanie wielu losowych znaków dla funkcji włączania strażnika podczas jej tworzenia. (Można ustawić dobry edytor, który zrobi to za Ciebie za każdym razem, gdy otworzysz nowy nagłówek.) Ale nawet bez tego nie napotkałem jeszcze żadnych problemów z konfliktami między bibliotekami.

James Kanze
źródło
11
Nie tylko zdalne uchwyty. Dowiązania twarde, dowiązania miękkie, konstrukcje zastępcze (w systemie Windows). To może być naprawdę brudne.
Tonny
45
Dlaczego kompilator nie może użyć sum kontrolnych SHA-1 lub MD5 do identyfikacji plików?
Sergey
29
Naprawdę nie widzę sensu nie umieszczania czegoś w standardzie, jeśli obsługuje to każdy główny kompilator. W standardzie są rzeczy, które są o wiele mniej obsługiwane. Ponadto wydaje się dość głupie narzekanie na problemy z krawędziami, gdy mówimy o plikach dołączanych, w przypadku których kolizje nazw plików są już ogromnym problemem. Byłoby miło, gdyby to żądanie w 100% bezproblemowej funkcji zostało zastosowane do koncepcji plików nagłówkowych #included.
TED
38
Jeśli twój kod zawiera jakiś plik z różnych lokalizacji za pośrednictwem dowiązań symbolicznych lub dziwnych montowań, to nie jest już przenośny. Dlatego argumentowanie, że pragma oncenie można przenośnie zaimplementować czegoś, co z natury nie jest przenośne (i nie powinno być nawet brane pod uwagę), to kolejny nonsens C ++ do góry nogami.
doc
7
@JoseAntonioDuraOlmos Zgadzam się, że dowiązania symboliczne są funkcją systemu operacyjnego, która jest poza zakresem języka C ++. Stąd pojawia się pytanie, dlaczego komisja C ++ powinna rozważyć coś, co jest poza zakresem języka? IMO próba zagwarantowania czegoś, co nie jest ich obowiązkiem, nie ma sensu. DOS obsługuje tylko 8 + 3 znaków na nazwę pliku, ale nikt nie twierdził, że #includenależy to usunąć, ponieważ można ślepo nadużywać dyrektywy. #pragma oncenie ogranicza w żaden sposób przenośności, pod warunkiem, że nie będziesz wykorzystywać dowiązań symbolicznych do przerywania kompilacji.
dokument
32

Sekcja §16.6 normy ( projekt N3936 ) opisuje #pragmadyrektywy jako:

Dyrektywa wstępnego przetwarzania formularza

# pragma pp-tokensopt new-line

powoduje, że implementacja zachowuje się w sposób zdefiniowany przez implementację. Takie zachowanie może spowodować niepowodzenie tłumaczenia lub spowodować, że tłumacz lub wynikowy program zachowa się w sposób niezgodny. Każda pragma, która nie została rozpoznana przez implementację, jest ignorowana.

Zasadniczo #pragma oncejest to instancja #pragmadyrektywy specyficzna dla implementacji i nie, nie jest to standard. Jeszcze.

Często jest szeroko obsługiwany przez większość "głównych kompilatorów", w tym GCC i Clang, dlatego czasami zaleca się unikanie standardowej wersji include-guards.

But
źródło
10
Zauważ, że możesz jednocześnie #pragmai #definestrażnika nagłówka.
Yakk - Adam Nevraumont
18
„Każda pragma, która nie została rozpoznana przez implementację, jest ignorowana” . Czy to oznacza, że ​​komunikat: Ostrzeżenie: nierozpoznana dyrektywa pragma jest niezgodna?
rodrigo
6
„i dlatego jest zalecanym sposobem uniknięcia schematu włączania osłon” - bardzo odważne stwierdzenie. To niestandardowy sposób, a korzyści z jego używania są nieliczne i prawie nie miały znaczenia z mojego doświadczenia, więc musiałem odebrać mi +1.
Alex
19
@Yakk: Jeśli ktoś pisze #defineochronę nagłówka, to też NIE ma powodu, żeby pisać #pragma once.
Nawaz
5
@Nawaz Kompilator może przechowywać pamięć podręczną każdego pliku (według ścieżki), który został #pragma onced, aw przypadku, gdy jest to #includeponownie d, może pominąć #include(nawet nie otwierać pliku). gcc robi to samo z ochroną nagłówków, ale jest bardzo, bardzo delikatne. Ten #pragmajest łatwy do zrobienia, ochrona nagłówka jest trudna.
Yakk - Adam Nevraumont