C ++ 'da satır içi işlevlerin faydaları?


254

C ++ 'da satır içi işlevleri kullanmanın avantajları / dezavantajları nelerdir? Sadece derleyicinin çıkardığı kodun performansını artırdığını görüyorum, ancak bugünün optimize edilmiş derleyicileri, hızlı CPU'ları, devasa bellekleri vb. bugün gerçekten avantajları var mı?


48
Bu, ortak bilginin yanlış olduğu sorulardan biridir. Herkes standart Comp Sci cevabı ile cevap verdi. (Inlining işlev çağrısı maliyetlerinden tasarruf sağlar ancak kod boyutunu artırır). Çöp. Derleyicinin daha fazla OPTİMİZASYON uygulaması için basit bir mekanizma sağlar.
Martin York

37
Bu, yorum olarak verilen cevaplardan biridir. Eğer gönderilen cevaplardan hiç hoşlanmıyorsanız, kendi cevabınızı gönderin ve nasıl gittiğini görün.
Dave Van den Eynde

10
Bu sorunun temeli kusurludur. C ++ satır içi işlevlerinin derleme sırasında satırlayıcı derleyicilerle ilgisi yoktur. Bu inlinebir c ++ anahtar kelime ve satır içi bir derleyici optimizasyon tekniği talihsiz bir durumdur. "Bu soruya bakın ben anahtar kelime yazmak gerekirken inlinebir işlev / yöntem için doğru cevap için".
deft_code

3
@JoseVega Bağlantınız karıştı

Yanıtlar:


143

Satır içi işlevler daha hızlıdır, çünkü parametreler ve dönüş adresi gibi yığınları açıp kapatmanıza gerek yoktur; ancak, ikili dosyalarınızı biraz daha büyütür.

Önemli bir fark yaratıyor mu? Modern donanımda çoğu için fark edilir derecede yeterli değil. Ancak bazı insanlar için yeterli olan bir fark yaratabilir.

Satır içi bir şeyi işaretlemek size satır içi olacağını garanti etmez. Sadece derleyiciye bir öneri. Bazen sanal bir işleve sahip olduğunuzda veya özyineleme olduğunda olduğu gibi mümkün değildir. Ve bazen derleyici onu kullanmamayı seçer.

Böyle bir durumun fark edilebilir bir fark yarattığını görebiliyordum:

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);

26
Şüphelendiğim gibi, inlining yukarıdakiler arasında bir fark yaratmaz. Gcc 4.01 ile derlenmiştir. Sürüm 1 satır içi kullanmaya zorlandı: 48.318u 1.042s 5: 51.39 99.4% 0 + 0k 0 + 0io 0pf + 0w Sürüm 2 satır içi zorunlu değil 348.311u 1.019s 5: 52.31 99.1% 0 + 0k 0 + 0io 0pf + 0w iyi bir örnek ortak bilgi yanlıştı.
Martin York

36
çağrının kendisi gerçekten önemli olsa da, bu sadece satır içi kullanarak elde ettiğiniz küçük kazançtır. En büyük kazanç, derleyicinin şimdi işaretçilerin birbirlerini takma adı görmediği, arayanın değişkenlerinin callee'de bittiği vb. Bu nedenle, aşağıdaki optimizasyon daha önemlidir.
Johannes Schaub - litb

31
Muhtemelen bu snippet'te bir fark yaratmaz çünkü fonksiyonun sonucu asla kullanılmaz ve fonksiyonun yan etkileri yoktur. Görüntü işlemede çizgiselleştirmede ölçülebilir bir performans artışı görüyoruz.
Süpürgelik

4
Hiçbir fark olmamasının nedeni, derleyicinin kendi isteğiyle satır içi olabilmesidir; veya kod küçük olduğundan, kod önceden getirme sorunu yoktur.
einpoklum

3
@einpoklum Derleyici bu nedenle tüm döngüyü bile optimize etmiş olabilir.
noɥʇʎԀʎzɐɹƆ

197

Avantajları

  • Kodunuzu gereken yerde satır içine alarak programınız işlev çağrısında ve dönüş parçalarında daha az zaman harcayacaktır. Kodunuz daha büyük olsa bile daha hızlı gitmesi gerekiyor (aşağıya bakın). Inlining önemsiz erişimciler etkili inlining bir örnek olabilir.
  • Satır içi olarak işaretleyerek, başlık dosyasına bir işlev tanımı koyabilirsiniz (yani, bağlayıcıdan şikayet etmeden birden çok derleme birimine dahil edilebilir)

Dezavantajları

  • Kodunuzu büyütebilir (örn. Önemsiz olmayan işlevler için satır içi kullanıyorsanız). Bu nedenle, derleyiciden çağrı ve optimizasyonları kışkırtabilir.
  • Enkapsülasyonunuzu hafifçe kırar, çünkü nesne işlemenizin iç kısmını ortaya çıkarır (ancak her "özel" üye de). Bu, bir PImpl deseninde satır içi kullanmamanız gerektiği anlamına gelir.
  • Enkapsülasyon 2'nizi hafifçe kırar: C ++ satır içi derleme zamanında çözülür. Bu, satır içi işlevin kodunu değiştirmeniz gerektiğinde, güncelleneceğinden emin olmak için tüm kodu yeniden derlemeniz gerekir (aynı nedenle, işlev parametreleri için varsayılan değerlerden kaçınırım)
  • Bir başlıkta kullanıldığında, başlık dosyanızı büyütür ve böylece kullanıcının umursamadığı kodla ilginç bilgileri (bir sınıf yöntemleri listesi gibi) seyreltir (bu, bir ancak sınıf gövdesinden sonra bir başlıkta tanımlayacak ve asla sınıf gövdesinin içinde tanımlamayacak).

Inlining Magic

  • Derleyici, satır içi olarak işaretlediğiniz işlevleri satır içinde olabilir veya olmayabilir; ayrıca, derleme veya bağlantı zamanında satır içi olarak işaretlenmemiş satır içi işlevler kullanmaya karar verebilir.
  • Satır içi, derleyici tarafından kontrol edilen ve bir ön işlemci makrosundan oldukça farklı olan bir kopyala / yapıştır gibi çalışır: Makro, zorla satır içi olacak, tüm ad alanlarını ve kodu kirletecek, kolayca hata ayıklanamayacak ve hatta yapılacak eğer derleyici onu verimsiz olarak yönetseydi.
  • Sınıfın kendi içinde tanımlanan bir sınıfın her yöntemi "satır içi" olarak kabul edilir (derleyici yine de satır içi yapmamaya karar verse bile)
  • Sanal yöntemlerin inlinable olması beklenmez. Yine de, bazen, derleyici nesnenin türünden emin olabilirse (yani nesne aynı işlev gövdesi içinde bildirildi ve oluşturuldu), derleyici tam olarak nesnenin türünü bildiğinden sanal bir işlev bile satır içine alınır.
  • Şablon yöntemleri / işlevleri her zaman satır içine alınmaz (bir başlıktaki varlığı onları otomatik olarak satır içi yapmaz).
  • "Satır içi" den sonraki adım şablon meta programlamasıdır. Yani kodunuzu derleme zamanında "satır içi" yaparak, derleyici bazen bir işlevin son sonucunu çıkarabilir ... Böylece karmaşık bir algoritma bazen bir tür return 42 ;ifadeye indirgenebilir . Bu benim için aşırı satırlık . Gerçek hayatta nadiren olur, derleme süresini uzatır, kodunuzu şişirmez ve kodunuzu daha hızlı hale getirir. Ancak kâse gibi, her yerde uygulamaya çalışmayın çünkü çoğu işlem bu şekilde çözülemez ... Yine de, bu yine de havalı ...
    :-p

Enkapsülasyonunuzu biraz kırdığını söylediniz. Lütfen bir örnek kullanarak açıklar mısınız?
Destructor

6
@PravasiMeet: Bu C ++. Diyelim ki, bir DLL / paylaşılan kitaplığı derleyen istemciye teslim edersiniz. Satır değişkeni foo, üye değişkeni X kullanarak ve Y işi yaparken istemcinin kodunda satır içine alınır. Üye değişkenini Z olarak değiştirdiğiniz DLL'nizin güncellenmiş bir sürümünü sağlamanız ve Y çalışmasına ek olarak YY çalışması eklemeniz gerektiğini varsayalım. kendi ikili yazdığınız kod değil ... Müşteri özel kod yasal erişim olmamasına rağmen, satırlama oldukça "genel" yapar.
paercebal

@paercebal İkinci ile son madde işareti noktanızla ilgili olarak, bir işlev şablonunun satır içi olmadığında bir örnek verebilir misiniz ? Şimdi kullanışlı bir referansım olmasa da, her zaman satır içi olduklarını düşündüm (basit bir test olsa da onaylıyor gibi görünüyor).
Konrad Rudolph

@KonradRudolph olarak görüyorum n4594: 3.2/6: There can be more than one definition of [..] inline function with external linkage [..] non-static function template. 5.1.5 / 6'da For a generic lambda, the closure type has a public inline function call operator member template. Ve 7.1.2/2: the use of inline keyword is to declare an inline functionburada çağrı sırasında fonksiyon gövdesini satır içine almanın bir önerisidir. Böylece, aynı şekilde davranabilseler bile, satır içi işlevlerin ve işlev şablonlarının hala ayrı, karıştırılabilen dikey kavramlar (yani satır içi işlev şablonu) olduğu
sonucuna varıyorum

kapsülleme bozuk mu? Nasıl yani? kapsülleme, hafızadaki gerçek nesneler için değil, programlamalar içindir. o noktada kimsenin umurunda değil. Bir kitaplığı dağıtsanız bile, derleyici satır içi yapmayı veya yapmamayı kendi başına seçebilir. Sonuç olarak yeni bir lib aldığınızda, o kütüphanedeki fonksiyonları ve nesneleri kullanan her şeyi yeniden derlemeniz yeterlidir.
FalcoGer

42

Arkaik C ve C ++ inlinegibi , registerolası bir optimizasyon hakkında derleyiciye bir öneri (öneri dışında bir şey).

Modern C ++ 'da, inlinebağlayıcıya farklı çeviri birimlerinde birden fazla tanım (bildirim değil) bulunursa, hepsi aynıdır ve bağlayıcı serbestçe birini tutabilir ve diğerlerini atabilir.

inline üstbilgi dosyasında bir işlev (ne kadar karmaşık veya "doğrusal" olursa olsun) tanımlanırsa, bağlayıcı tarafından "çoklu tanım" hatası almadan birden çok kaynağın dahil edilmesine izin vermek için zorunludur.

Sınıf içinde tanımlanan üye işlevler, şablon işlevlerinde olduğu gibi (genel işlevlerin aksine) varsayılan olarak "satır içi" dir.

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

FileA.h dosyasının iki .cpp dosyasına eklendiğini ve iki örneğiyle sonuçlandığını unutmayın afunc(). Bağlayıcı bunlardan birini atar. Hayır inlinebelirtilirse, bağlayıcı şikayet edecektir.


16

Inlining, derleyiciye görmezden gelmek için bir öneridir. Küçük kod parçaları için idealdir.

İşleviniz eğikse, aslında ayrı bir işlevi çağırmak yerine işlev çağrısının yapıldığı koda eklenir. Bu, gerçek aramayı yapmak zorunda olmadığınız için hıza yardımcı olabilir.

Ayrıca, bir çağrıdan kaynaklanan yeni talimatlarla boru hattını yeniden yüklemek zorunda olmadıkları için CPU'lara boru hattı ile yardımcı olur.

Tek dezavantaj, ikili boyutun artmasıdır, ancak işlevler küçük olduğu sürece, bu çok fazla önemli değildir.

Bu tür kararları bugünlerde derleyicilere bırakma eğilimindeyim (zaten akıllı olanlar). Onları yazan insanlar, altta yatan mimariler hakkında çok daha ayrıntılı bilgiye sahip olma eğilimindedir.


12

Satır içi işlev, derleyiciler tarafından kullanılan optimizasyon tekniğidir. Bir işlev satır içi bir işlev yapmak için işlev prototip yerine satır içi anahtar kelime başına olabilir. Satır içi işlev derleyiciye bu işlevin kodda kullanıldığı yere işlevin tam gövdesini eklemesini bildirir.

Avantajları: -

  1. Fonksiyon çağırma yükü gerektirmez.

  2. Ayrıca işlev çağırma sırasında yığındaki push / pop değişkenlerinin yükünü de kaydeder.

  3. Aynı zamanda bir fonksiyondan geri dönüş çağrısı yükünü de kaydeder.

  4. Talimat önbelleğini kullanarak referansın yerini artırır.

  5. Astardan sonra derleyici ayrıca belirtilmişse işlem içi optimizasyon uygulayabilir. Bu en önemlisidir, bu şekilde derleyici artık ölü kod eliminasyonuna odaklanabilir, şube tahmini, indüksiyon değişken eliminasyonu vb. Üzerinde daha fazla stres verebilir.

Bu konuda daha fazla bilgi edinmek için bu bağlantıyı takip edebilirsiniz http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html


4
1) Bu bir öneri değil, bir talimattır 2) Yaygın olarak kullanılan bir işlev çok fazla satır içi ise kod boyutundaki artış nedeniyle daha fazla önbellek kaybına neden olabilir
Flekso

3
Sondaki bağlantı kişisel blogunuz mu? Eğer öyleyse böyle ilan etmelisiniz, aksi takdirde spam gibi görünür.
Flekso

6

Paylaşılan kitaplık oluştururken satır içi işlevlerin çok önemli olduğunu eklemek istiyorum. İşaretleme işlevi satır içi olmadan, ikili biçimde kitaplığa aktarılacaktır. Dışa aktarılırsa, semboller tablosunda da bulunur. Diğer tarafta, ne kütüphane ikililerine ne de semboller tablosuna satır içi işlevler verilmez.

Kitaplığın çalışma zamanında yüklenmesi amaçlandığında kritik olabilir. İkili uyumlu kitaplıkları da etkileyebilir. Bu gibi durumlarda satır içi kullanmayın.


@Johnsyweb: Cevabımı dikkatle okuyun. Bir yürütülebilir dosya oluştururken söyledikleriniz doğrudur. Ancak derleyici, inlinepaylaşılan bir kütüphane oluştururken göz ardı edemez !
doc

4

Optimizasyon sırasında birçok derleyici, işaretlemeseniz bile işlevleri satır içi yapar. Genellikle derleyicinin bilmediği bir şey biliyorsanız, işlevleri doğru olarak satır olarak işaretlemeniz gerekir, çünkü genellikle doğru kararı kendisi verebilir.


Birçok derleyici de bunu yapmayacak, örneğin MSVC bunu siz söylemedikçe
yapmayacaktır

4

inlineüstbilgi dosyasına ve #includebu üstbilgi dosyasını bir tanım kuralını ihlal etmeden birden çok kaynak dosyaya bir işlev tanımı yerleştirmenize olanak tanır .


3

Genel olarak konuşursak, bugünlerde herhangi bir modern derleyicinin herhangi bir şeyi satır içine almaktan endişe duyması neredeyse bir zaman kaybıdır. Derleyici, kodun kendi analizi ve derleyiciye iletilen optimizasyon bayrakları belirtimleriniz yoluyla tüm bu hususları sizin için optimize etmelidir. Hızı önemsiyorsanız, derleyiciye hızı optimize etmesini söyleyin. Alanı önemsiyorsanız, derleyiciye alanı optimize etmesini söyleyin. Başka bir cevabın belirttiği gibi, iyi bir derleyici gerçekten mantıklıysa otomatik olarak satır içi olacaktır.

Ayrıca, diğerlerinin de belirttiği gibi, satır içi kullanmak hiçbir şeyin satır içi olmasını garanti etmez. Bunu garanti etmek istiyorsanız, bunu yapmak için satır içi işlev yerine bir makro tanımlamanız gerekir.

İçermeyi zorlamak için bir makro ne zaman satır içi ve / veya tanımlanır? - Yalnızca uygulamanın genel performansını etkilediği bilinen kodun kritik bir bölümü için kanıtlanmış ve gerekli kanıtlanmış bir hız artışınız olduğunda.


… Eğer alanı önemsiyorsanız, derleyiciye alanı optimize etmesini söyleyin - derleyiciye hız için optimize etmesini söylemek C ++ ve C ile daha küçük ikili dosyalara yol açabilir , benzer şekilde derleyiciye alanı optimize etmesini söylemek daha hızlı yürütme ile sonuçlanabilir. Bu özellikler her zaman reklamı yapılan gibi çalışmaz. insanlar programlarının bazı yönlerini bir derleyicinin genelleştirilmiş yorumlarından daha iyi anlayabilme yeteneğine sahiptir (ki bu da kullanılabilir şekilde hızlı kalmalıdır). insan müdahalesi kötü bir şey olmak zorunda değildir.
justin

3

Her şey performansla ilgili değil. Hem C ++ hem de C, donanımın üstünde oturan gömülü programlama için kullanılır. Örneğin, bir kesme işleyicisi yazarsanız, kodun ek kayıtlar ve / veya bellek sayfaları değiştirilmeden bir kerede çalıştırılabileceğinden emin olmanız gerekir. İşte o zaman satır içi kullanışlı olur. İyi derleyiciler hız gerektiğinde kendilerini "satır içi" yaparlar, ancak "satır içi" onları zorlar.


1

Aynı kütüphaneye satır içi işlevlerin inlining ile aynı sorun düştü. Sıralı fonksiyonların kütüphanede derlenmediği anlaşılıyor. sonuç olarak, çalıştırılabilir kütüphane kütüphanenin inline fonksiyonunu kullanmak istiyorsa linker "tanımsız referans" hatası verir. (bana Qt kaynağını gcc 4.5 ile derledi.


1

Neden tüm fonksiyonları varsayılan olarak satır içi yapmıyorsunuz? Çünkü bu bir mühendislik ödülü. En az iki tür "optimizasyon" vardır: programı hızlandırmak ve programın boyutunu (bellek kapladığı alanı) azaltmak. Inlining genellikle işleri hızlandırır. Fonksiyon çağrısı tepsisinden kurtulur, istiflemeden sonra parametreleri yığından çekmekten kaçınır. Bununla birlikte, aynı zamanda programın bellek ayak izini büyütür, çünkü her işlev çağrısı artık işlevin tam koduyla değiştirilmelidir. İşleri daha da karmaşık hale getirmek için, CPU'nun sık kullanılan bellek parçalarını ultra hızlı erişim için CPU'daki bir önbellekte sakladığını unutmayın. Programın bellek görüntüsünü yeterince büyük yaparsanız, programınız önbelleği verimli bir şekilde kullanamaz ve en kötü durumda satır içi program aslında programınızı yavaşlatabilir.


1

Bilgisayar bilimleri profesörümüz bizi bir c ++ programında asla satır içi kullanmaya çağırdı. Neden sorulduğunda, modern derleyicilerin ne zaman satır içi otomatik olarak kullanılacağını tespit etmesi gerektiğini bize açıkladı.

Yani evet, satır içi, mümkün olan her yerde kullanılacak bir optimizasyon tekniği olabilir, ancak görünüşe göre bu, bir işlevi zaten satır içi yapmak mümkün olduğunda zaten sizin için yapılmış bir şeydir.


5
Profesörünüz maalesef tamamen yanlış. inlineC ++ 'da çok farklı iki anlamı vardır - bunlardan sadece biri optimizasyonla ilgilidir ve profesörünüz bu konuda doğrudur. Ancak, İkinci Tanım Kuralınıinline yerine getirmek için genellikle ikinci anlamı gereklidir .
Konrad Rudolph

-1

Dan Sonuç başka tartışma burada:

Satır içi işlevlerle ilgili herhangi bir dezavantaj var mı?

Görünüşe göre, satır içi işlevlerini kullanırken yanlış bir şey yok.

Ancak aşağıdaki noktalara dikkat etmek gerekir!

  • Satır aralığının aşırı kullanımı aslında programları yavaşlatabilir. Bir işlevin boyutuna bağlı olarak, satır içine almak kod boyutunun artmasına veya azalmasına neden olabilir. Çok küçük bir erişimci fonksiyonunun satır içine alınması genellikle kod boyutunu azaltırken, çok büyük bir fonksiyonun satır içine alınması kod boyutunu önemli ölçüde artırabilir. Modern işlemcilerde, komut önbelleğinin daha iyi kullanılması nedeniyle küçük kod genellikle daha hızlı çalışır. - Google Yönergeleri

  • Satır içi işlevlerin hız avantajları, işlev boyutu büyüdükçe azalma eğilimindedir. Bir noktada, işlev çağrısının ek yükü, işlev gövdesinin yürütülmesiyle karşılaştırıldığında küçük olur ve fayda kaybolur - Kaynak

  • Satır içi bir işlevin çalışmayabileceği birkaç durum vardır:

    • Değer döndüren bir işlev için; bir return ifadesi varsa.
    • Herhangi bir değer döndürmeyen bir işlev için; bir loop, switch veya goto ifadesi varsa.
    • Bir işlev özyinelemeli ise. -Kaynak
  • __inlineAnahtar kelime, optimize seçeneği belirtirseniz bir işlev yalnızca satır içine yerleştirilmiş neden olur. Optimizasyon belirtilirse, __inlineonurlandırılıp onurlandırılmayacağı satır içi iyileştirici seçeneğinin ayarına bağlıdır. Varsayılan olarak, optimize edici her çalıştırıldığında satır içi seçeneği etkindir. Optimizasyon belirtirseniz, __inlineanahtar kelimenin yoksayılmasını istiyorsanız noinline seçeneğini de belirtmeniz gerekir . -Kaynak


3
Satır içi derleyici için bir ipucu değil, bir komut olsaydı doğru olurdu. Derleyici aslında satır içi ne olacağına karar verir.
Martin York

1
@LokiAstari Satır içi derleyiciye istek olduğunu biliyorum. Benim argümanım derleyiciye ipucu ise en iyisine karar vermek için derleyiciye bırakmalıyız. Satır içi kullansanız bile satır içi neden herhangi bir şekilde kullanılır? Ayrıca Microsoft'umun _forceinline'ı tanıttığını merak ediyorum.
Krishna Oza

@krish_oza: Buraya yorumum. Bu cevap hakkında. Buradaki cevap tamamen yanlış. Derleyici , satır içi kodun satır içinde kodlanıp kodlanmayacağını belirlemek için inlineanahtar kelimeyi dikkate almaz . Derleyici satır içi için anahtar kelimeyi kullansaydı doğruydu (yalnızca bağlantı amacıyla çoklu tanımları işaretlemek için kullanılır).
Martin York
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.