Na spotkaniu Oulu ISO C ++ w 2016 r ., Komitet normalizacyjny przegłosował propozycję o nazwie Inline Variables w języku C ++ 17.
Mówiąc prościej, czym są zmienne wbudowane, jak działają i do czego są przydatne? W jaki sposób należy deklarować, definiować i stosować zmienne wbudowane?
const
.inline
słowo kluczowe robi dla funkcji. Słowoinline
kluczowe zastosowane do funkcji ma jeszcze jeden istotny skutek, który przekłada się bezpośrednio na zmienne.inline
Funkcja, która jest przypuszczalnie zadeklarowana w pliku nagłówkowym, nie spowoduje „duplikat symbol” błędy w czasie łącza, nawet jeśli nagłówek dostaje#include
d przez wielu jednostek tłumaczeniowych. Słowoinline
kluczowe zastosowane do zmiennych da dokładnie ten sam wynik. Koniec.inline
jest tylko słabym, niewiążącym żądaniem skierowanym do optymalizatora. Kompilatory mogą nie wstawiać żądanych funkcji i / lub wbudowywać te, których nie dodałeś adnotacji. Prawdziwym celeminline
słowa kluczowego jest raczej obejście wielu błędów definicji.Odpowiedzi:
Pierwsze zdanie wniosku:
Gwarantowanym efektem
inline
zastosowania do funkcji jest umożliwienie identycznego zdefiniowania funkcji, z powiązaniami zewnętrznymi, w wielu jednostkach tłumaczeniowych. W praktyce oznacza to zdefiniowanie funkcji w nagłówku, która może być zawarta w wielu jednostkach tłumaczeniowych. Wniosek rozszerza tę możliwość na zmienne.Tak więc, w praktyce (teraz zaakceptowana) propozycja umożliwia użycie
inline
słowa kluczowego do zdefiniowaniaconst
zmiennej zakresu przestrzeni nazw powiązania zewnętrznego lub dowolnegostatic
elementu członkowskiego danych klasy w pliku nagłówkowym, dzięki czemu wiele definicji, które powstają, gdy ten nagłówek zostanie uwzględniony w Wiele jednostek tłumaczeniowych jest w porządku z linkerem - po prostu wybiera jedną z nich.Aż do C ++ 14 włącznie wewnętrzny mechanizm do tego służył, aby wspierać
static
zmienne w szablonach klas, ale nie było wygodnego sposobu używania tego mechanizmu. Trzeba było uciekać się do takich sztuczekOd C ++ 17 i nowszych uważam, że można po prostu pisać
… W pliku nagłówkowym.
Wniosek zawiera sformułowanie
… Co pozwala na dalsze uproszczenie powyższego do just
… Jak zauważył TC w komentarzu do tej odpowiedzi.
Ponadto
constexpr
specyfikator implikujeinline
statyczne elementy składowe danych, a także funkcje.Uwagi:
¹ Ponieważ funkcja
inline
ma również wpływ na optymalizację, kompilator powinien preferować zamianę wywołań tej funkcji na bezpośrednie podstawienie kodu maszynowego funkcji. Tę wskazówkę można zignorować.źródło
Kath::hi
) nie muszą być stałymi.const
ograniczenie zostało całkowicie zniesione.static std::string const hi = "Zzzzz...";
?Zmienne wbudowane są bardzo podobne do funkcji wbudowanych. Sygnalizuje linkerowi, że powinno istnieć tylko jedno wystąpienie zmiennej, nawet jeśli zmienna jest widoczna w wielu jednostkach kompilacji. Konsolidator musi upewnić się, że nie są tworzone więcej kopii.
Zmienne wbudowane mogą służyć do definiowania zmiennych globalnych w bibliotekach zawierających tylko nagłówki. Przed C ++ 17 musieli stosować obejścia (funkcje wbudowane lub hacki szablonów).
Na przykład jednym obejściem jest użycie singletona Meyera z funkcją wbudowaną:
Takie podejście ma pewne wady, głównie w zakresie wydajności. Tego narzutu można by uniknąć dzięki rozwiązaniom opartym na szablonach, ale łatwo jest je pomylić.
Dzięki zmiennym wbudowanym możesz je bezpośrednio zadeklarować (bez otrzymania błędu konsolidatora z wieloma definicjami):
Oprócz bibliotek zawierających tylko nagłówki, istnieją inne przypadki, w których mogą pomóc zmienne wbudowane. Nir Friedman omawia ten temat w swoim wykładzie na CppCon: Co programiści C ++ powinni wiedzieć o globals (i konsolidatorze) . Część dotycząca zmiennych wbudowanych i obejść zaczyna się od 18m9s .
Krótko mówiąc, jeśli musisz zadeklarować zmienne globalne, które są wspólne dla jednostek kompilacji, zadeklarowanie ich jako zmiennych wbudowanych w pliku nagłówkowym jest proste i pozwala uniknąć problemów z obejściami przed C ++ 17.
(Na przykład nadal istnieją przypadki użycia singletona Meyera, jeśli jawnie chcesz mieć leniwą inicjalizację).
źródło
Minimalny działający przykład
Ta niesamowita funkcja C ++ 17 pozwala nam:
constexpr
: Jak zadeklarować extern constexpr?main.cpp
notmain.hpp
notmain.cpp
Skompiluj i uruchom:
GitHub upstream .
Zobacz także: Jak działają zmienne wbudowane?
Standard C ++ dotyczący zmiennych wbudowanych
Standard C ++ gwarantuje, że adresy będą takie same. C ++ 17 N4659 standardowa wersja robocza 10.1.6 „Specyfikator wbudowany”:
cppreference https://en.cppreference.com/w/cpp/language/inline wyjaśnia, że jeśli
static
nie jest podane, ma link zewnętrzny.Implementacja zmiennych inline GCC
Możemy obserwować, jak jest realizowany za pomocą:
który zawiera:
i
man nm
mówi ou
:więc widzimy, że jest do tego dedykowane rozszerzenie ELF.
Przed C ++ 17:
extern const
Przed C ++ 17, a także w C, możemy osiągnąć bardzo podobny efekt za pomocą
extern const
, co doprowadzi do użycia jednej lokalizacji pamięci.Wady
inline
to:constexpr
tą techniką,inline
pozwala tylko na to: Jak zadeklarować constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub upstream .
Alternatywy tylko dla nagłówków przed C ++ 17
Nie są one tak dobre, jak
extern
rozwiązanie, ale działają i zajmują tylko jedną lokalizację w pamięci:constexpr
Funkcja, ponieważconstexpr
zakładainline
iinline
pozwala (siły) definicja pojawiać się na każdej jednostki tłumaczeniowej :i założę się, że każdy przyzwoity kompilator wbuduje wywołanie.
Można również użyć
const
lubconstexpr
statyczną zmienną całkowitą, na przykład:ale nie możesz robić takich rzeczy, jak pobieranie jego adresu, bo inaczej zostanie użyty odr, zobacz także: https://en.cppreference.com/w/cpp/language/static "Stałe statyczne składowe " i Definiowanie stałych danych statycznych członków
do
W C sytuacja jest taka sama, jak w C ++ przed C ++ 17, przesłałem przykład pod adresem: Co oznacza „statyczny” w C?
Jedyną różnicą jest to, że w C ++
const
implikuje tostatic
dla globals, ale nie w C: C ++ semantyka `static const` vs` const`Jakikolwiek sposób, aby w pełni go wbudować?
DO ZROBIENIA: czy istnieje sposób na pełne wstawienie zmiennej bez użycia jakiejkolwiek pamięci?
Podobnie jak robi to preprocesor.
Wymagałoby to w jakiś sposób:
Związane z:
Testowany w Ubuntu 18.10, GCC 8.2.0.
źródło
inline
nie ma prawie nic wspólnego z wstawianiem, ani dla funkcji, ani dla zmiennych, pomimo samego słowa.inline
nie mówi kompilatorowi, aby cokolwiek wstawiał. Mówi linkerowi, aby upewnił się, że istnieje tylko jedna definicja, która jest tradycyjnie wykonywana przez programistę. Więc "Jakiś sposób, aby to w pełni wbudować?" to przynajmniej zupełnie niezwiązane pytanie.