Jedną z moich głównych skarg na C ++ jest to, jak trudno w praktyce przekraczać obiekty biblioteki standardowej poza granicami biblioteki dynamicznej (tj. Dll / so).
Biblioteka std jest często tylko nagłówkiem. Co jest świetne do robienia niesamowitych optymalizacji. Jednak w przypadku bibliotek DLL często są one budowane z różnymi ustawieniami kompilatora, które mogą wpływać na wewnętrzną strukturę / kod kontenerów biblioteki standardowej. Na przykład w MSVC jedna biblioteka DLL może się kompilować z włączonym debugowaniem iteratora, podczas gdy inna kompilacja jest wyłączona. Te dwie biblioteki dll mogą napotykać problemy z przekazywaniem standardowych pojemników. Jeśli ujawniam się std::string
w interfejsie, nie mogę zagwarantować, że kod, którego używa klient, jest std::string
dokładnie zgodny z kodem mojej biblioteki std::string
.
Prowadzi to do trudnych problemów z debugowaniem, bólów głowy itp. Albo sztywno kontrolujesz ustawienia kompilatora w swojej organizacji, aby zapobiec tym problemom, albo używasz prostszego interfejsu C, który nie będzie miał takich problemów. Lub określ swoim klientom oczekiwane ustawienia kompilatora, których powinni użyć (co jest do bani, jeśli inna biblioteka określa inne ustawienia kompilatora).
Moje pytanie brzmi, czy C ++ 11 próbował zrobić coś, aby rozwiązać te problemy?
DLL
s. PomiędzySO
s zawsze działało dobrze.Odpowiedzi:
Masz rację, że czegokolwiek STL - a właściwie wszystkiego z jakiejkolwiek biblioteki stron trzecich, która jest szablonowana - najlepiej unikać w każdym publicznym API C ++. Chcesz również przestrzegać długiej listy reguł na stronie http://www.ros.org/reps/rep-0009.html#definition, aby zahamować uszkodzenie ABI, co sprawia, że programowanie publicznych interfejsów API C ++ jest obowiązkowe.
Odpowiedź dotycząca C ++ 11 brzmi: nie, ten standard tego nie dotyka. Bardziej interesujące jest dlaczego nie? Odpowiedź brzmi, ponieważ C ++ 17 bardzo go dotyka, a do wdrożenia modułów C ++ potrzebujemy wyeksportowanych szablonów do działania, a do tego potrzebujemy kompilatora typu LLVM, takiego jak clang, który może zrzucić całą AST na dysk, a następnie wykonuj wyszukiwania zależne od dzwoniącego, aby obsłużyć wiele przypadków naruszających ODR w każdym dużym projekcie C ++ - który, nawiasem mówiąc, zawiera wiele kodu GCC i ELF.
Na koniec widzę wiele komentarzy nienawiści do MSVC i pro-GCC. Są one bardzo źle poinformowane - GCC na ELF jest zasadniczo i nieodwracalnie niezdolne do wytworzenia prawidłowego i poprawnego kodu C ++. Powodów jest wiele i legion, ale szybko przytoczę jeden przykład: GCC na ELF nie może bezpiecznie tworzyć rozszerzeń Pythona napisanych przy użyciu Boost.Python, w których więcej niż jedno rozszerzenie oparte na Boost.Python jest ładowane do Pythona. Wynika to z faktu, że ELF ze swoją globalną tablicą symboli C jest po prostu niezdolny do zaprojektowania, aby zapobiec naruszeniom ODR powodującym awarie segregacji, podczas gdy PE i MachO, a nawet proponowana specyfikacja modułów C ++ wszystkie używają tabel symboli dla poszczególnych modułów - co przy okazji oznacza również znacznie szybsze czasy inicjowania procesu. I jest o wiele więcej problemów: zobacz StackOverflow, na który ostatnio odpowiedziałemhttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 na przykład, gdy przypadki wyjątków C ++ są nieodwracalnie fundamentalnie uszkodzone na ELF.
Ostatni punkt: w odniesieniu do interakcji różnych STL jest to wielki problem dla wielu dużych użytkowników korporacyjnych próbujących łączyć biblioteki stron trzecich, które są ściśle zintegrowane z niektórymi implementacjami STL. Jedynym rozwiązaniem jest nowy mechanizm dla C ++ do obsługi interpolacji STL, a gdy już są dostępne, równie dobrze możesz naprawić interpolację kompilatora, abyś mógł (na przykład) mieszać MSVC, GCC i clang skompilować pliki obiektów i wszystko po prostu działa . Obejrzałbym wysiłek C ++ 17 i zobaczyłem, co się tam pojawi w ciągu najbliższych kilku lat - byłbym zaskoczony, gdyby nic nie zrobiło.
źródło
Specyfikacja nigdy nie miała tego problemu. Jest tak, ponieważ ma koncepcję zwaną „regułą jednej definicji”, która nakazuje, aby każdy symbol miał dokładnie jedną definicję w uruchomionym procesie.
Biblioteki DLL systemu Windows naruszają ten wymóg. Dlatego są te wszystkie problemy. Więc to Microsoft musi to naprawić, a nie komitet normalizacyjny C ++. Unix nigdy nie miał tego problemu, ponieważ biblioteki współdzielone działają tam inaczej i domyślnie są zgodne z jedną regułą definicji (możesz to jawnie złamać, ale oczywiście robisz to tylko wtedy, gdy wiesz, że możesz sobie na to pozwolić i musisz wycisnąć kilka dodatkowych cykli).
Biblioteki DLL systemu Windows naruszają jedną regułę definicji, ponieważ:
Unix korzystający z eksportu w formacie ELF domyślnie importuje wszystkie wyeksportowane symbole, aby uniknąć pierwszego problemu i nie rozróżnia między statycznie i dynamicznie rozwiązanymi symbolami aż do statycznego czasu łącza, aby uniknąć drugiego.
Innym problemem są flagi kompilatora. Ten problem występuje w przypadku każdego programu złożonego z wielu jednostek kompilacyjnych, biblioteki dynamiczne nie muszą być zaangażowane. Jednak w systemie Windows jest znacznie gorzej. W systemie Unix tak naprawdę nie ma znaczenia, czy łączysz statycznie czy dynamicznie, nikt i tak nie łączy statycznego standardowego środowiska wykonawczego (w Linuksie może to nawet być nielegalne) i nie ma specjalnego środowiska uruchomieniowego debugowania, więc jedna kompilacja jest wystarczająca. Ale sposób, w jaki Microsoft wdrożył statyczne i dynamiczne łączenie, środowisko uruchomieniowe debugowania i zwalniania oraz kilka innych opcji oznacza, że spowodowały one kombinatoryczną eksplozję potrzebnych wariantów bibliotek. Znów problem z platformą, a nie z językiem C ++.
źródło
Nie.
Dużo pracy dzieje się w celu zastąpienia systemu nagłówka, funkcji zwanej modułami, która może mieć na to wpływ, ale z pewnością nie jest duża.
źródło