C ++ 11, std lib nesnelerini dinamik / paylaşımlı kütüphane sınırları arasında geçirme konusundaki endişelerini ele aldı mı? (yani, borçlar falan)?


34

C ++ hakkındaki en büyük şikayetlerimden biri, pratikte std kütüphanesi nesnelerinin dinamik kütüphanenin (yani dll / so) sınırlarının dışına aktarılmasının ne kadar zor olduğu.

Std kütüphanesi genellikle sadece başlıktır. Bazı harika optimizasyonlar yapmak için harika. Bununla birlikte, dll'ler için, genellikle bir std kütüphane konteynırlarının iç yapısını / kodunu etkileyebilecek farklı derleyici ayarlarıyla oluşturulurlar. Örneğin, MSVC'de bir dll, bir başkası onunla birlikte derlenirken yineleyicinin hata ayıklamasıyla oluşturulabilir. Bu iki eşya, etrafta std kaplarını geçen sorunlara rastlayabilir. std::stringArayüzümde ifşa edersem, müşterinin kullandığı kodun std::stringkütüphanemle tam olarak eşleştiğini garanti edemem std::string.

Bu, sorunları, baş ağrıları, vb. Hata ayıklamayı zorlaştırır. Bu sorunları önlemek için kuruluşunuzdaki derleyici ayarlarını sıkı bir şekilde denetlersiniz veya bu sorunlara sahip olmayacak daha basit bir C arayüzü kullanırsınız. Veya müşterilerinize, kullanmaları gereken beklenen derleyici ayarlarını belirtin (başka bir kitaplığın diğer derleyici ayarlarını belirlemesi durumunda berbat).

Sorum şu ki, C ++ 11 bu sorunları çözmek için bir şeyler yapmaya çalıştı mı?


3
Sorunuzun cevabını bilmiyorum ama endişelerinizin paylaşıldığını söyleyebilirim; Projelerimde C ++ 'ı neden kullanmayacağımın anahtarıdır, çünkü her son potansiyel verimlilik döngüsünde ABI kararlılığına değer veriyoruz.
Donal Fellows

2
Lütfen ayırt edin. DLLS arasında zor . S arasında SOher zaman iyi çalıştı.
Jan Hudec

1
Açıkçası, bu bir C ++ tek sorun değil. Bu sorunun diğer dillerde de olması mümkündür.
MrFox

2
@JanHudec SO'lar arasında, belirttiğiniz gibi neredeyse hiç sihirli bir şekilde çalışmadığını garanti edebilirim. Sembol görünürlüğü ve isim yönetiminin sıklıkla nasıl çalıştığı göz önüne alındığında, bir problemden daha fazla yalıtılmış olabilirsiniz, ancak farklı bayraklar / vb. İle bir derleme yapılır ve bunu bir programda diğer bayraklarla bağlayabileceğinizi varsayarsanız felaket için bir reçetedir.
sdg

3
@sdg: Varsayılan bayraklar ve varsayılan görünürlük ile çalışır. Onları değiştirip başını belaya sokarsan, bu senin sorunun ve başkasının değil.
Jan Hudec

Yanıtlar:


20

Herhangi bir STL - aslında, esasen, herhangi bir üçüncü taraf kitaplığından şablon olan herhangi bir şeyin - herhangi bir genel C ++ API'sinde engellenmesi konusunda haklısınız. Ayrıca, genel C ++ API'lerinin programlanmasını bir görev haline getiren ABI kırılmasını önlemek için http://www.ros.org/reps/rep-0009.html#definition adresindeki uzun kurallar listesine de uymak istersiniz .

Ve C ++ 11 ile ilgili cevap hayır, bu standart buna dokunmuyor. Daha ilginç olan, neden olmasın? Bunun cevabı, C ++ 17'nin buna çok dokunmasıdır ve C ++ Modüllerinin uygulanabilmesi için dışa aktarılmış şablonlara ihtiyacımız vardır ve bunun için tam AST'yi diske ve sonra boşaltabilecek clang gibi bir LLVM tipi derleyiciye ihtiyacımız vardır. Herhangi bir büyük C ++ projesinde birçok ODR ihlal eden olayı ele almak için arayanlara bağımlı aramalar yapın; bu arada birçok GCC ve ELF kodu da içerir.

Son olarak, birçok MSVC nefreti ve GCC yanlısı yorumu görüyorum. Bunlar çok yanlış biçimlendirilmiş - ELF'deki GCC temelde ve geri çevrilemez bir şekilde geçerli ve doğru C ++ kodu üretemiyor. Bunun nedenleri çok ve lejyondur, ancak hızlı bir şekilde bir örnek vereceğim: ELF'deki GCC, Boost.Python'a dayanarak birden fazla uzantının Python'a yüklendiği Boost.Python kullanılarak yazılan Python uzantılarını güvenli bir şekilde üretemez. Bunun nedeni, küresel C sembol tablosuna sahip ELF'nin, segment arızalarına neden olan ODR ihlallerini önleme tasarımında basitçe yetersiz kalmasıdır; oysa ki PE ve MachO ve gerçekten de önerilen C ++ Modülleri spesifikasyonunun tümü, modül başına sembol tablolarını kullanır - bu arada, tesadüfen çok daha hızlı bir işlem süreci anlamına gelir. Ve daha birçok sorun var: son zamanlarda cevapladığım bir StackOverflow bakınhttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 örneğin C ++ istisnası fırlatmasının ELF'de geri dönüşü olmayan bir şekilde bozulduğu durumlarda.

Son nokta: Farklı STL'lerin birlikte çalışılmasıyla ilgili olarak, bu, bazı STL uygulamalarına sıkı sıkıya entegre olan üçüncü taraf kütüphanelerini karıştırmaya çalışan birçok büyük kurumsal kullanıcı için büyük bir acıdır. Tek çözüm, C ++ 'nın STL birlikte çalışmayı işleyebilmesi için yeni bir mekanizmadır ve onlar da çalışmakta iken derleyici birlikte çalışmasını da düzeltebilirsiniz, böylece MSVC, GCC ve clang derlenmiş nesne dosyalarını karıştırabilirsiniz (hepsi çalışır) . C ++ 17 çalışmasını izlerdim ve önümüzdeki birkaç yıl içinde neyin ortaya çıktığını görürdüm - eğer bir şey olmazsa şaşırırdım.


Harika tepki! Sadece Clang'ın pencerelerin uyumluluğunu arttırdığını ve iyi bir standart derleyici ayarlayabileceğini umuyorum. C ++ 'nın metinsel içerme / başlık sistemi korkunçtur, modüllerin C ++ kod organizasyonunu basitleştirdiği, derleme zamanlarını kademeli olarak hızlandırdığı ve ODR ihlal eden mandallarla derleyici birlikte çalışabilirliğini geliştirdiği günü sabırsızlıkla bekliyorum.
Alessandro Stamatto

3
Şahsen, aslında derleyici zamanlarında önemli bir artış bekliyordum . Modül içi AST'yi hızlı bir şekilde geçmek çok zordur ve muhtemelen bellek içi paylaşılan bir bellek önbelleğine ihtiyacımız olacak. Ancak, kötü olan hemen hemen her şey daha iyi olur. BTW, başlık dosyaları kesinlikle kalıyor, mevcut C ++ modülleri başlık dosyaları için 1'den 1'e arabirim haritalarına sahip. Ayrıca, otomatik olarak oluşturulan arabirim dosyaları yasal C ++ olacaktır, bu nedenle eski bir başlık basitçe C makrolarını filtreler ve arabirim dosyaları olarak dağıtır. Güzel ha?
Niall Douglas

Güzel! Modüller hakkında çok şüphem var. Modül sistemi, Sembolik İçermeye Karşı Metinsel İçermeyi dikkate alacak mı? Mevcut içerme yönergesi ile derleyici her kaynak dosya için on binlerce kod satırını tekrar tekrar derlemek zorundadır. Modüller sistemi ileriye dönük beyanlarda bulunulmadan birgün kod verir mi? Yapı araçlarını iyileştirecek mi / kolaylaştıracak mı?
Alessandro Stamatto

2
-1 tüm üçüncü taraf şablonlarının şüpheli olduğunu öne sürdüğü için. Konfigürasyonu değiştirmek, konfigüre edilen şeyin bir şablon olup olmamasından bağımsızdır.
DeadMG

1
@Alessandro: Önerilen C ++ modülleri, C makrolarını açıkça devre dışı bırakır. Şablonları veya nowt kullanabilirsiniz. Önerilen arayüzler yasal C ++, yalnızca otomatik olarak üretildi ve yeniden istifleme hızı için isteğe bağlı olarak önceden derlenebilir, yani mevcut önceden derlenmiş başlıklar üzerinde herhangi bir hız artışı beklemeyin. Son iki soru, aslında bilmiyorum: değişir :)
Niall Douglas

8

Şartname hiç bu konuda bir şey yapmadı. Bunun nedeni, her bir sembolün çalışan işlemde tam olarak bir tanımı olmasını zorunlu kılan “bir tanım kuralı” kavramına sahip olmasıdır.

Windows DLL dosyaları bu gereksinimi ihlal ediyor. Bu yüzden tüm bu problemler var. Bu yüzden, C ++ standardizasyon komitesi değil, düzeltilmesi Microsoft'a kalmış. Unix bu sorunu hiç yaşamadı, çünkü paylaşılan kütüphaneler orada farklı şekilde çalışıyorlar ve varsayılan olarak tek bir tanım kuralına uyuyorlar (açıkça kırabilirsin, ama açıkçası sadece onu karşılayabileceğini ve fazladan fazla döngü atman gerektiğini biliyorsan yaparsın).

Windows DLL'ler bir tanım kuralını ihlal ediyor çünkü:

  • Statik bağlantı süresi boyunca bir sembolün hangi dinamik kütüphaneden kullanılacağını kodlarlar ve bunları tanımlayan kütüphanede statik olarak semboller çözerler. Dolayısıyla, aynı zayıf sembol birden fazla paylaşılan kütüphanede ve bu kütüphanelerde tek işlemde kullanılmaya başlandıysa, dinamik bağlayıcının bu sembolleri birleştirme şansı yoktur. Genellikle bu semboller statik üyeler veya şablon örneklerinin sınıf engelleridir ve farklı DLL'lerde kodlar arasında örnekler geçerken sorunlara neden olurlar.
  • Derleme sırasında zaten sembolün dinamik kütüphaneden içe aktarılıp aktarılmayacağını kodlarlar. Bu yüzden bazı kütüphanelere statik olarak bağlanmış olan kod, aynı kütüphaneye dinamik olarak bağlı olan kodla uyumlu değildir.

ELF formatı dışa aktarmayı kullanan Unix, ilk sorunu önlemek için dışa aktarılan tüm sembolleri dolaylı olarak içe aktarır ve ikincisini önlemek için statik bağlantı zamanına kadar statik ve dinamik olarak çözülmüş semboller arasında ayrım yapmaz.


Diğer konu ise derleyici bayrakları. Bu konu, çoklu derleme birimlerinden oluşan herhangi bir program için mevcuttur, dinamik kütüphanelerin dahil olması gerekmez. Ancak Windows'ta çok daha kötü. Unix'te statik veya dinamik olarak bağlantı kurup bağlamadığınız önemli değildir, hiç kimse standart çalışma zamanını herhangi bir şekilde statik olarak bağlamaz (Linux'ta yasadışı bile olabilir) ve özel bir hata ayıklama zamanı yoktur, bu nedenle bir yapı yeterince iyidir. Ancak Microsoft'un statik ve dinamik bağlantı kurma, çalışma zamanını ve hata ayıklama ve serbest bırakma yöntemlerini uygulama yöntemleri, gerekli kitaplık varyantlarının birleştirici patlamasına neden olduğu anlamına gelir. Yine C ++ dil sorunu yerine platform sorunu.


2
@DougT .: GCC'nin bununla hiçbir ilgisi yok. ABI platformu var. ELF'de, çoğu Unice tarafından kullanılan nesne formatı, paylaşılan kütüphaneler, tüm görünür sembolleri verir ve verdikleri tüm sembolleri alır. Dolayısıyla, birden fazla kütüphanede bir şey üretilirse, dinamik linker herkes için ilk tanımı kullanacaktır. Sade, şık ve çalışıyor.
Jan Hudec

1
@ MartinBa: Birleşecek bir şey yok, fakat ilk etapta birleştirilmesi gerekmediği sürece, aynı olduğu sürece matrat yapmıyor. Evet, bir ELF platformunda uyumsuz derleyici ayarları kullanırsanız, her yerde ve her yerde aynı karışıklığı elde edersiniz. Paylaşılan kütüphaneleri kullanmasanız bile, burada biraz konu dışı.
Jan Hudec

1
@Jan - Cevabınızla alakalı. Yazıyorsunuz: "... bir tanım kuralı ... Windows DLL'leri bu gereksinimi ihlal ediyor ... paylaşılan kütüphaneler [UNix'te] farklı çalışıyor ..." ancak sorulan soru std-lib ile ilgili problemlerle ilgili (başlıklarda tanımlanmış) ve Unix'te sorun yok olmasının sebebi SO ile DLL ile ilgisi yok ama aslında, Unix'te (görünüşe göre) standart kütüphanenin sadece bir uyumlu sürümü varken, Windows MS'de uyumsuz (hata ayıklama) sürümleri seçildi. (genişletilmiş kontrol vb. ile).
Martin Ba

1
@MartinBa: Hayır, Windows'ta sorun olmasının ana nedeni, Windows'ta kullanılan dışa aktarma / içe aktarma mekanizmasının, tüm durumlarda statik üyeleri ve şablon sınıfının engelli sınıfını düzgün şekilde birleştirememesi ve statik ve dinamik olarak bağlı sembolleri birleştirememesidir. Daha çok çoklu kütüphane değişkenleri tarafından daha da kötüleşti, ancak asıl sorun C ++ 'ın Windows dinamik linkerin sahip olmadığı linkerden esnekliğe ihtiyacı var.
Jan Hudec

4
Bence bu DLL belirtiminin kırıldığı ve Msft'in 'onu düzeltmesi' talebinin yanlış olduğunu düşünüyorum. DLL'lerin C ++ 'nın bazı özelliklerini desteklememesi, DLL özelliklerinin bir hatası değildir. DLL'ler, giriş noktalarını makine koduna ('işlev çağrıları') ve veri bloğuna maruz bırakan, dil-nötr, satıcı-nötr bir paketleme mekanizması ve ABI'dır. Hiçbir zaman belirli bir dilin gelişmiş özelliklerini yerel olarak desteklemeyi amaçlamamışlardır. Bu, Msft’in ya da bazı kişilerin başka bir şey olmasını istemelerinin DLL şartnamesinin hatası değil.
Euro Micelli,

6

Yok hayır.

Modül adı verilen ve bunun üzerinde etkisi olabilecek, ancak kesinlikle büyük olmayan bir özellik olan başlık sisteminin yerini alacak çok iş var.


2
Başlık sisteminin bu konuda herhangi bir etkisi olacağını sanmıyorum. Sorunlar, Windows DLL'lerin bir tanım kuralını ihlal ettiği anlamına gelir (bu, C ++ belirtimlerini izlemedikleri anlamına gelir; bu nedenle C ++ komitesi bu konuda hiçbir şey yapamaz) ve Windows'ta C ++ komitesinin yapabileceği çok sayıda standart çalışma zamanı varyantları vardır. ya da hiçbir şey yapmayın.
Jan Hudec

1
Hayır, yapmazlar. Nasıl olabilirler, şartname bile böyle bir şeyden bahsetmiyor. Bunun dışında, bir (Windows) programı Windows dlls ile bağlantılı olduğunda, ODR tatmin edicidir: tüm görünür (verilen) semboller ODR'ye uymalıdır.
Paul Michalik

@PaulMichalik C ++ bağlantıyı (aşama 9) kapsar ve bana en azından DLL / SO'ların yüklenme zamanını bağlamanın 9. aşamada kaldığı anlamına geliyor. Bu, dış bağlantıya sahip sembollerin (dışa aktarılıp aktarılmayacağına bakılmaksızın) bağlanması ve uygun olması gerektiği anlamına geliyor. ODR. LoadLibrary / dlopen ile dinamik bağlantı, açık bir şekilde bu gereksinimlere uymuyor.
oyun5353

@ bames53: IMHO, teknik özellikler bu tür açıklamalara izin vermeyecek kadar zayıf. Bir .dll / .so kendi başına bir "program" olarak görülebilir. Daha sonra kurallar yerine getirildi. Çalışma zamanında diğer "programları" yüklemek gibi bir şey, standart ile o kadar anlaşılmaz ki, bununla ilgili ifadeler oldukça keyfidir.
Paul Michalik

@PaulMichalik Bir çalıştırılabilir yükleme zamanı bağlantısı gerektiriyorsa, yükleme zamanı bağlantısı öncesinde çözülmemiş kalan harici varlıklar vardır ve yürütme için gereken bilgiler eksiktir. LoadLibrary ve Dlopen dışında faz 9. parçası olmalıdır oldukça net bir şekilde bağlayan Spec ama yük zamanlıdır
bames53
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.