Myślę, że czegoś tu brakuje.
funkcja statyczna?
Zadeklarowanie funkcji statycznej spowoduje, że będzie ona „ukryta” w jednostce kompilacji.
Nazwa mająca zasięg przestrzeni nazw (3.3.6) ma łącze wewnętrzne, jeśli jest nazwą
- zmienna, funkcja lub szablon funkcji, który jest jawnie zadeklarowany jako statyczny;
3.5 / 3 - C ++ 14 (n3797)
Gdy nazwa ma powiązania wewnętrzne, do jednostki, którą ona oznacza, można odnieść się za pomocą nazw z innych zakresów w tej samej jednostce tłumaczeniowej.
3.5 / 2 - C ++ 14 (n3797)
Jeśli zadeklarujesz tę statyczną funkcję w nagłówku, wszystkie jednostki kompilacji, w tym ten nagłówek, będą miały własną kopię funkcji.
Rzecz w tym, że jeśli wewnątrz tej funkcji znajdują się zmienne statyczne, każda jednostka kompilacji zawierająca ten nagłówek będzie miała również swoją własną, osobistą wersję.
funkcja inline?
Zadeklarowanie go inline sprawia, że jest on kandydatem do wstawiania (w dzisiejszych czasach w C ++ nie znaczy to wiele, ponieważ kompilator będzie wbudowany lub nie, czasami ignorując fakt, że słowo kluczowe inline jest obecne lub nieobecne):
Deklaracja funkcji (8.3.5, 9.3, 11.3) ze specyfikatorem wbudowanym deklaruje funkcję wbudowaną. Specyfikator wbudowany wskazuje implementacji, że podstawianie w wierszu treści funkcji w punkcie wywołania ma być preferowane w stosunku do zwykłego mechanizmu wywoływania funkcji. Implementacja nie jest wymagana, aby wykonać to podstawienie w linii w momencie wywołania; jednakże, nawet jeśli to podstawianie w wierszu zostanie pominięte, pozostałe reguły funkcji wbudowanych, zdefiniowane w 7.1.2, powinny być nadal przestrzegane.
7.1.2 / 2 - C ++ 14 (n3797)
W nagłówku ma to interesujący efekt uboczny: wbudowaną funkcję można zdefiniować wiele razy w tym samym module, a linker po prostu połączy „je” w jeden (jeśli nie zostały one wstawione z powodu kompilatora).
W przypadku zmiennych statycznych zadeklarowanych wewnątrz standard wyraźnie podaje jedną i tylko jedną z nich:
Statyczna zmienna lokalna w zewnętrznej funkcji wbudowanej zawsze odnosi się do tego samego obiektu.
7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)
(funkcje są domyślnie extern, więc jeśli nie oznaczysz swojej funkcji jako statycznej, dotyczy to tej funkcji)
Ma to tę zaletę, że jest „statyczne” (tj. Można je zdefiniować w nagłówku) bez wad (istnieje najwyżej raz, jeśli nie jest wstawione)
statyczna zmienna lokalna?
Statyczne zmienne lokalne nie mają żadnych powiązań (nie można do nich odwoływać się z nazwy poza swoim zakresem), ale mają statyczny czas przechowywania (tj. Są globalne, ale ich konstrukcja i niszczenie podlegają określonym regułom).
statyczne + wbudowane?
Mieszanie inline i static będzie miało konsekwencje, które opisałeś (nawet jeśli funkcja jest wbudowana, zmienna statyczna wewnątrz nie będzie, a skończysz z tyloma zmiennymi statycznymi, ile masz jednostek kompilacji, w tym definicję funkcji statycznych ).
Odpowiedz na dodatkowe pytanie autora
Odkąd napisałem pytanie, wypróbowałem to w Visual Studio 2008. Próbowałem włączyć wszystkie opcje, które sprawiają, że VS działa zgodnie ze standardami, ale możliwe, że niektóre mi ominęły. Oto wyniki:
Gdy funkcja jest tylko „wbudowana”, istnieje tylko jedna kopia zmiennej statycznej.
Gdy funkcja jest „statyczna w wierszu”, kopii jest tyle, ile jest jednostek tłumaczeniowych.
Prawdziwe pytanie brzmi teraz, czy tak ma być, czy też jest to cecha charakterystyczna kompilatora Microsoft C ++.
Więc przypuszczam, że masz coś takiego:
void doSomething()
{
static int value ;
}
Musisz zdać sobie sprawę, że zmienna statyczna wewnątrz funkcji, po prostu jest to zmienna globalna ukryta dla wszystkich oprócz zakresu funkcji, co oznacza, że tylko funkcja, w której jest zadeklarowana, może do niej dotrzeć.
Umieszczenie funkcji niczego nie zmieni:
inline void doSomething()
{
static int value ;
}
Będzie tylko jedna ukryta zmienna globalna. Fakt, że kompilator będzie próbował wstawić kod, nie zmieni faktu, że istnieje tylko jedna globalna zmienna ukryta.
Teraz, jeśli twoja funkcja jest zadeklarowana jako statyczna:
static void doSomething()
{
static int value ;
}
Wtedy jest „prywatna” dla każdej jednostki kompilacji, co oznacza, że każdy plik CPP, w tym nagłówek, w którym zadeklarowana jest funkcja statyczna, będzie miał swoją prywatną kopię funkcji, w tym własną prywatną kopię globalnej ukrytej zmiennej, a więc tyle zmiennych, ile istnieją jednostki kompilacji zawierające nagłówek.
Dodanie „inline” do funkcji „static” ze zmienną „static” wewnątrz:
inline static void doSomething()
{
static int value ;
}
ma taki sam skutek, jak brak dodania tego słowa kluczowego „inline”, jeśli chodzi o zmienną statyczną wewnątrz.
Zatem zachowanie VC ++ jest poprawne, a Ty mylisz prawdziwe znaczenie słów „inline” i „static”.
inline void doSomething() { static int value ; }
, funkcja ma połączenie zewnętrzne; jest to naruszenie ODR, jeśli pojawia się w nagłówku zawierającym dwie różne jednostkiinline
nie może naruszać ODR.Uważam, że kompilator tworzy wiele kopii zmiennej, ale konsolidator wybiera jedną i sprawia, że wszystkie inne odwołują się do niej. Podobne wyniki miałem, gdy próbowałem eksperymentować z utworzeniem różnych wersji funkcji wbudowanej; jeśli funkcja nie była w rzeczywistości wbudowana (tryb debugowania), wszystkie wywołania trafiały do tej samej funkcji, niezależnie od pliku źródłowego, z którego zostały wywołane.
Pomyśl przez chwilę jak kompilator - jak mogłoby być inaczej? Każda jednostka kompilacji (plik źródłowy) jest niezależna od pozostałych i może być kompilowana oddzielnie; każdy musi zatem stworzyć kopię zmiennej, myśląc, że jest jedyna. Konsolidator ma możliwość przekraczania tych granic i dostosowywania odniesień zarówno dla zmiennych, jak i funkcji.
źródło
Odpowiedź Marka Ransoma okazała się pomocna - że kompilator tworzy wiele kopii zmiennej statycznej, ale konsolidator wybiera jedną i wymusza ją we wszystkich jednostkach tłumaczeniowych.
Gdzie indziej znalazłem to:
Zobacz [dcl.fct.spec] / 4
Nie mam kopii normy do sprawdzenia, ale zgadza się ona z moim doświadczeniem w badaniu zespołu w VS Express 2008
źródło
Tak ma być. „static” mówi kompilatorowi, że chcesz, aby funkcja była lokalna w jednostce kompilacji, dlatego chcesz, aby jedna kopia na jednostkę kompilacji i jedna kopia zmiennych statycznych na instancję funkcji.
„inline” używane do informowania kompilatora, że funkcja ma być wbudowana; obecnie przyjmuje to po prostu jako „w porządku, jeśli istnieje kilka kopii kodu, po prostu upewnij się, że jest to ta sama funkcja”. Więc wszyscy współużytkują zmienne statyczne.
Uwaga: ta odpowiedź została napisana w odpowiedzi na odpowiedź zamieszczoną w oryginalnym plakacie.
źródło
inline
powoduje, że funkcja jest wstawiana lub można mieć wiele kopii?inline
nie powoduje inliningu, po prostu sugeruje to i pozwala na więcej niż jedną definicję (ale nie w tej samej jednostce kompilacji).Odkąd napisałem pytanie, wypróbowałem to w Visual Studio 2008. Próbowałem włączyć wszystkie opcje, które sprawiają, że VS działa zgodnie ze standardami, ale możliwe, że niektóre mi ominęły. Oto wyniki:
Gdy funkcja jest tylko „wbudowana”, istnieje tylko jedna kopia zmiennej statycznej.
Gdy funkcja jest „statyczna w wierszu”, kopii jest tyle, ile jest jednostek tłumaczeniowych.
Prawdziwe pytanie brzmi teraz, czy tak ma być, czy też jest to ideowa synchronizacja kompilatora Microsoft C ++.
źródło
Inlining oznacza, że kod wykonywalny (instrukcje) jest wbudowany w kod funkcji wywołującej. Kompilator może to zrobić niezależnie od tego, czy o to poprosiłeś. Nie ma to wpływu na zmienne (dane) zadeklarowane w funkcji.
źródło
Wierzę, że otrzymasz jedną na jednostkę tłumaczeniową. W rzeczywistości masz wiele wersji tej funkcji (i jej zadeklarowanej zmiennej statycznej), po jednej dla każdej jednostki tłumaczeniowej zawierającej nagłówek.
źródło
Oprócz wszelkich problemów projektowych, wszystko to może oznaczać, ponieważ już z tym utknąłeś, powinieneś używać statycznego w tym przypadku, a nie inline. W ten sposób wszyscy mają te same zmienne. (Funkcja statyczna)
źródło
Statyczny oznacza, że jedna kopia jest rozpowszechniana w całym programie, ale inline oznacza, że wymaga tego samego kodu przez kilka razy w tym samym programie, więc nie jest możliwe uczynienie zmiennej statyczną wewnątrz funkcji wbudowanej.
źródło