Satır içi işlev ne zaman kullanılır ve ne zaman kullanılmaz?


185

Satır içi derleyici bir ipucu veya istek olduğunu biliyorum ve onun işlev çağrısı tepegöz önlemek için kullanılır.

Öyleyse, bir fonksiyonun bir satır içi çizgisine aday olup olmadığını hangi temelde belirleyebilir? Hangi durumda satır içi kalmamak gerekir?


11
inlineC + CFLAGS-O3 -funroll-loops -finline-functions
acemi

1
Satır içi kullanmamanın bir nedeni, bazı hata ayıklayıcıların bir kırılma noktası ayarlamanıza veya satır içi bir işleve adım atmanıza izin vermemesidir.
Rob deFriesse


5
Bir işlevin inline olup olmayacağını belirlememelisiniz. Derleyici bunu yapsın; sizden daha iyidir (ve her aramanın ortamına bağlı olarak işlevleri seçici olarak satır içine alabilir).
David Thornley

@DavidThornley Bazen, tanım cpp dosyasındaysa, O3 bayrağı ayarlı olsa bile, derleyici işlevi satır içinde yapmaz. Bu yüzden, takip ettiğim başparmak kuralı, bir astarı ve ayrıca döngüsüz bu işlevleri satır içi yapmaktır.
talekeDskobeDa

Yanıtlar:


210

Bir işlev çağrısının maliyetinden kaçınmak hikayenin sadece yarısıdır.

yapmak:

  • inlineyerine kullan#define
  • çok küçük işlevler aşağıdakiler için iyi adaylardır inline: daha hızlı kod ve daha küçük yürütülebilir dosyalar (kod önbelleğinde kalma şansı daha yüksektir)
  • işlev küçüktür ve çok sık çağrılır

yok:

  • büyük işlevler: daha büyük yürütülebilir dosyalara yol açar, bu da çağrı yükünden kaynaklanan daha hızlı yürütme işleminden bağımsız olarak performansı önemli ölçüde etkiler
  • G / Ç bağlantılı satır içi işlevler
  • işlev nadiren kullanılır
  • yapıcılar ve yıkıcılar: boş olsa bile, derleyici onlar için kod üretir
  • kitaplıklar geliştirirken ikili uyumluluğu bozma:
    • varolan bir işlevi satır içinde
    • satır içi işlevi değiştirme veya satır içi işlevi satır içi olmayan yapma: kitaplığın önceki sürümü eski uygulamayı çağırır

bir kütüphane geliştirirken, bir sınıfı gelecekte genişletilebilir yapmak için:

  • gövde boş olsa bile satır içi olmayan sanal yıkıcı ekle
  • tüm kurucuları satıriçi yapma
  • sınıf değere göre kopyalanamazsa, kopya oluşturucu ve atama işlecinin satır içi olmayan uygulamalarını yazma

inlineAnahtar kelimenin derleyiciye bir ipucu olduğunu unutmayın : derleyici bir işlevi satır içine almamaya karar verebilir inlineve ilk etapta işaretlenmemiş satır içi işlevleri kullanmaya karar verebilir . Genellikle işaretleme işlevinden kaçınırım inline(belki çok çok küçük işlevler yazarken).

Performans hakkında, akıllıca yaklaşım (her zamanki gibi) uygulamayı profillemek, daha sonra da inlinebir darboğazı temsil eden bir dizi işlevdir.

Referanslar:


EDIT: Bjarne Stroustrup, C ++ Programlama Dili:

Bir işlev olarak tanımlanabilir inline. Örneğin:

inline int fac(int n)
{
  return (n < 2) ? 1 : n * fac(n-1);
}

inlineBelirteci o bir çağrı için kodu oluşturmak girişiminde gerektiğini derleyiciye bir ipucu fac()kez işlev kodu bırakmasını ve sonra her zamanki işlev çağrısı mekanizması yoluyla çağırmaktan daha inline ziyade. Akıllı bir derleyici 720çağrı için sabit üretebilir fac(6). Karşılıklı olarak yinelenen satır içi işlevler, girdiye bağlı olan veya olmayan satır içi işlevler, vb inline. Olasılığı , bir işlevin her çağrısının aslında satır içi olduğunu garanti etmeyi imkansız hale getirir . Bir derleyicinin akıllılık derecesi yasallaştırılamaz, bu nedenle bir derleyici 720diğerini 6 * fac(5), hatta diğeri eğik olmayan bir çağrı oluşturabilir fac(6).

Alışılmadık derecede akıllı derleme ve bağlantı tesislerinin yokluğunda satırlamayı mümkün kılmak için, satır içi bir işlevin tanımı –ve sadece beyanı değil- kapsam dahilinde olmalıdır (§9.2). Bir inlinetanımlayıcı bir işlevin anlambilimini etkilemez. Özellikle, bir satır içi işlev hala benzersiz bir adrese sahiptir ve bu nedenle staticsatır içi bir işlevin değişkenleri (§7.1.2) vardır.

EDIT2: ISO-IEC 14882-1998, 7.1.2 İşlev tanımlayıcıları

Bir inlinebelirteci içeren işlev bildirimi (8.3.5, 9.3, 11.4) satır içi işlevi bildirir. Satır içi belirteç, uygulamaya, çağrı noktasında fonksiyon gövdesinin satır içi ikamesinin olağan fonksiyon çağrısı mekanizmasına tercih edileceğini belirtir. Çağrı sırasında bu satır içi yerine koymayı gerçekleştirmek için bir uygulama gerekli değildir; ancak, bu satır içi ikame atlanmış olsa bile, 7.1.2'de tanımlanan satır içi işlevler için diğer kurallara yine de uyulacaktır.


34
inlinederleyicinin ipucundan çok daha fazlasıdır. Çoklu tanımlarla ilgili dil kurallarını değiştirir. Ayrıca, statik verilere sahip olmak, bir işlevi satır içine almaktan kaçınmak için dökme bir neden değildir. Uygulama, işlevin bildirilip bildirilmediğine bakılmaksızın, her işlev statik için tek bir statik nesne ayırmakla yükümlüdür inline. Sınıflar, satır içi kurucuları ve sanal yıkıcıları varsa hala genişletilebilir. Ve boş parantez yıkıcı, bazen satır içi bırakmanın iyi bir fikir olduğu tek sanal işlevdir .
CB Bailey

2
Bu işlev mutlaka satır içine (yani ingilizce benim ana dilim değil) bitmez anlamında bir ipucu. İşaretli işlevlerdeki statik hakkında inline, sonuç işlevin satır içine alınmamasıdır: çağrı için ücret ödersiniz ve ayrıca işlevi içeren ve çağıran her çeviri birimi kodun ve statik değişkenlerin kendi kopyasını alır. Bir kütüphane geliştirirken kurucuları ve yıkıcıları
satırlaştırmamanın

14
Buna "derleyiciye bir ipucu" demek yanlış. Gerçekte, inlinederleyici böyle hissediyorsa işlev dışı satırlar satır içine alınabilir. Ve inlinederleyici bunları satır içi yapmamaya karar verirse işlevler satır içi olmaz. Charles Bailey'in dediği gibi, dil kurallarını değiştirir. Bunu bir optimizasyon ipucu olarak düşünmektense, tamamen farklı bir kavram olarak düşünmek daha doğru olur. inlineAnahtar kelime birden tanımlarını sağlamak için derleyici, ve başka bir şey söyler. "Satır içi" optimizasyonu, işaretlenmiş olsun veya olmasın hemen hemen her işleve uygulanabilir inline.
jalf

26
Sadece, Stroustrup "satır içi belirleyici derleyiciye bir ipucu" yazdığında, onu alıntılamakla suçlandığım için şaşırdım. Her neyse, bu cevabı mümkün olduğunca çok referansla desteklemek için elimden geleni yaptım
Gregory Pakosz

2
@GregoryPakosz: Ama hepimiz inlinefonksiyon satır içi elde etmek için kullanmıyoruz . Bazen ODR'yi dolaşmak gibi diğer faydaları da isteriz.
Yörüngedeki Hafiflik Yarışları

57

inlineoptimizasyonla çok az ilgisi vardır. inlineDerleyici için, verilen işlev programda birden çok kez oluşursa hata üretmemeye yönelik bir talimattır ve tanımın, kullanılan her çeviride gerçekleşeceği ve göründüğü her yerde tam olarak aynı tanıma sahip olacağına dair bir sözdür.

Yukarıdaki kurallar göz önüne alındığında, inlinevücudu sadece bir deklarasyonun gerekeceği konusunda ekstra bağımlılıklar dahil etmeyi gerektirmeyen kısa fonksiyonlar için uygundur. Tanımla her karşılaşıldığında, ayrıştırılması ve gövdesinin kodunun oluşturulabilmesi için tek bir kaynak dosyasında yalnızca bir kez tanımlanan bir işlev üzerinde bir derleyici yükü anlamına gelmesi gerekir.

Bir derleyici, seçtiği herhangi bir işlev çağrısını satır içine alabilir (yani, işleve yapılan bir çağrıyı o işlevin eylemini gerçekleştiren kodla değiştirebilir). Eskiden "açık bir şekilde" çağrı ile aynı çeviri biriminde bildirilmeyen bir işlevi satır içi yapamamıştı, ancak bağlantı süresi optimizasyonunun artan kullanımı ile bu bile doğru değil. Eşit derecede doğrudur, işaretli işlevlerin inlinesatır içi olmaması da mümkündür.


Bunun C ++ 'nın kasıtlı bir özelliğinden daha mutlu bir tesadüf olduğunu hissediyorum. Fikir, C'nin 'statik' global değişkenlerine çok benzer. Yine de çok ilginç bir cevap. Keşke sadece iç bağlantıyı belirtmek için 'dahili' gibi bir anahtar kelime kullanmışlar.
Rehno Lindeque

+1. @Rehno: Ne dediğinden emin değilim. Bağlantı inlineanahtar kelimeyle ne ilgisi var ? Ve mutlu tesadüf nedir?
jalf

@jalf: Yorumumu retrospektte okurken bunun oldukça belirsiz olduğunu ve iyi düşünülmediğini anlıyorum. Aynı işlevi birden fazla dosyada tanımlamak, 'statik' işlevini bildirerek sayılabilen bir bağlayıcı hatasıyla sonuçlanır. Bununla birlikte, 'satır içi', aynı şeyi, 'statik' gibi iç bağlantıya sahip olmadıkları ince farklarla yapmanıza izin verir. Bunun aslında bir tesadüf olduğundan şüpheliyim çünkü dil uygulayıcıları / tasarımcıları başlık dosyalarında bildirilen işlevlerle özel bir şeyler yapmaları gerektiğini fark ettiler ve bu da 'satır içi'.
Rehno Lindeque

4
Performans, satır içi kullanmak için baskın neden olduğundan, yorumunuzun neden bu kadar çok oy aldığından emin değilim.
gast128

10

Derleyiciye bir işlevi satır içi yapmasını söylemek bir optimizasyondur ve en önemli optimizasyon kuralı, erken optimizasyonun tüm kötülüğün kökü olmasıdır. Her zaman net kod yazın (verimli algoritmalar kullanarak), ardından programınızı profilleyin ve yalnızca çok uzun süren işlevleri optimize edin.

Belirli bir işlevin çok kısa ve basit olduğunu ve sıkı bir iç döngüde onbinlerce kez denirse, iyi bir aday olabilir.

Yine de şaşırabilirsiniz - birçok C ++ derleyicisi sizin için otomatik olarak küçük işlevleri sıraya koyacaktır - ve satır içi isteğinizi de yoksayabilirler.


Gerçekten, bazı derleyicilerin 'inline'ı tamamen gizlice görmezden geldiğine ve sadece' __inline 'ya da' __force_inline'a cevap verdiğine dair şüphelerim var. Sanırım bu kötüye kullanımı caydırmak!
Rehno Lindeque

Genellikle durum böyle değil. satır içi sadece bir ipucu, ancak çoğu derleyicinin ciddiye aldığı bir ipucu. Derleyiciyi /FAcs, -stam olarak ne yaptığını görmek için derleme dilini nesne koduyla birlikte ( Visual Studio'da, GCC'de) yayınlayacak şekilde ayarlayabilirsiniz . Deneyimlerime göre, bu derleyiciler inline anahtar kelimesini oldukça ağır bir şekilde tartıyor.
Crashworks

1
Bu ilginç, çünkü benim deneyimime göre ne g ++ ne de VC tartmak inlineanahtar kelime. Diğer bir deyişle, işlevin satır içine inlinealınmış olduğunu görürseniz ve tanımlayıcıyı ondan kaldırırsanız , yine de satır içine alınır. Bunun aksini gösteren spesifik örnekleriniz varsa lütfen paylaşın!
Pavel Minaev

4
inlineanahtar kelime "kodu temizle" yi nasıl engeller? "Erken optimizasyon" içindeki anahtar kelime optimizasyon değil , erken . Optimizasyonlardan aktif olarak * kaçınmanız gerektiğini söylemek sadece saçmadır. Bu teklifin amacı, gerekli olmayan optimizasyonlardan kaçınmanız ve kod üzerinde zararlı yan etkilere sahip olmanızdır (daha az bakım yapılabilir hale getirmek gibi). inlineAnahtar kelimenin kodu daha az bakım yapılabilir hale nasıl yapacağını veya bir işleve eklemek için nasıl zararlı olabileceğini göremiyorum .
jalf

3
jalf, bazen bir işlevi satır içine almak, kodunuzu daha hızlı değil daha yavaş hale getirir. Bir örnek, fonksiyonun kodunuzdaki birkaç farklı yerden çağrılmasıdır; işlev satır içi değilse, farklı bir yerden çağrıldığında yönerge önbelleğinde olabilir ve dal tahmincisi zaten ısınmış olabilir. Verimliliği her zaman artıran bazı desenler vardır, bu yüzden bunları kullanmak asla acıtmaz. Inlining bunlardan biri değil. Genellikle performans üzerinde hiçbir etkisi yoktur, bazen yardımcı olur ve bazen acıtır. Tavsiyemin arkasında duruyorum: önce profil, sonra satır içi.
dmazzoni

5

Bunu öğrenmenin en iyi yolu, programınızın profilini oluşturmak ve birçok kez çağrılan ve CPU döngüleri olarak yanan küçük işlevleri işaretlemektir inline. Buradaki anahtar kelime "küçük" tir - fonksiyon çağrısı yükü, fonksiyonda harcanan zamana kıyasla ihmal edilebilir olduğunda, bunları satır içine almak anlamsızdır.

Önerebileceğim diğer bir kullanım, bir önbelleği alakalı hale getirmek için yeterince sık performans kritik kodunda çağrılan küçük işlevleriniz varsa, bunları da satır içi yapmanız gerekir. Yine, bu profilin size söyleyebileceği bir şey.


4

Erken optimizasyon tüm kötülüklerin köküdür!

Genel bir kural olarak, genellikle yalnızca "alıcılar" ve "ayarlayıcılar" ı sıralıyorum. Kod çalıştıktan ve kararlı hale geldikten sonra, profil oluşturma hangi işlevlerin satır içi işlemden fayda sağlayabileceğini gösterebilir.

Öte yandan, çoğu modern derleyici oldukça iyi optimizasyon algoritmalarına sahiptir ve sizin için satır içi olması gerekenleri sıraya koyacaktır.

Güven verici - satır içi tek satırlık işlevler yazın ve daha sonra diğerleri hakkında endişelenin.


2

Satır içi işlevleri olabilir yığını haline argümanları etme gereğini ortadan kaldırarak kod performansını artırmak. söz konusu işlev kodunuzun kritik bir parçasıysa, projenizin optimizasyon bölümünde satır içi değil satır içi karar vermeniz gerekir,

c ++ sss'deki satır içi satırlar hakkında daha fazla bilgi edinebilirsiniz


1

Çoğu zaman satır içi işlevleri bir optimizasyon olarak değil, kodu daha okunabilir yapmak için kullanıyorum. Bazen kodun kendisi yorumlardan, açıklayıcı adlardan vb. Daha kısa ve anlaşılması kolaydır. Örneğin:

void IncreaseCount() { freeInstancesCnt++; }

Okuyucu, kodun tüm anlambilimini hemen bilir.


0

Genelde, 3-4 basit ifadeyle satır içi olarak işlev yaptığım bir başparmak kuralını izlerim. Ancak bunun derleyiciye bir ipucu olduğunu hatırlamakta fayda var. Satır içi yapılıp yapılmayacağı son çağrısı sadece derleyici tarafından yapılır. Eğer bu kadar çok ifadeden daha fazlası varsa, aptal bir derleyicide olduğu gibi satır içi beyan etmeyeceğim.


0

En iyi yol, satır içi ve satır içi değil için oluşturulan talimatları incelemek ve karşılaştırmak olacaktır. Ancak, atlamak her zaman güvenlidir inline. Kullanmak inlineistemediğiniz bir soruna yol açabilir.


0

Satır içi kullanılıp kullanılmayacağına karar verirken genellikle aşağıdaki fikri aklımda tutarım: Modern makinelerde bellek gecikmesi ham hesaplamalardan daha büyük bir darboğaz olabilir. Sıklıkla çağrılan satır içi işlevlerin yürütülebilir boyutu büyüttüğü bilinmektedir. Ayrıca, böyle bir işlev CPU'nun kod önbelleğinde saklanabilir ve bu da bu koda erişilmesi gerektiğinde önbellek kaçırma sayısını azaltır.

Bu nedenle, kendiniz karar vermelisiniz: Satır içi oluşturma, üretilen makine kodunun boyutunu artırır veya azaltır mı? İşlevin çağrılmasının önbellek kaybına neden olma olasılığı nedir? Kod boyunca biberli ise, olasılığın yüksek olduğunu söyleyebilirim. Tek bir sıkı döngü ile sınırlıysa, olasılık umarım düşüktür.

Genellikle körüklediğim durumlarda satır içi kullanıyorum. Ancak, performans konusunda gerçekten endişe duyduğunuz yerlerde profil oluşturma önemlidir. Ayrıca, derleyicinin gerçekten ipucunu alıp almadığını kontrol etmek isteyebilirsiniz.

  • Sıkı döngüde çağrılan kısa rutinler.
  • Çok temel erişimciler (alma / ayarlama) ve sarma işlevleri.
  • Başlık dosyalarındaki şablon kodu maalesef satır içi ipucunu otomatik olarak alır.
  • Makro gibi kullanılan kısa kod. (Ör min () / maks ())
  • Kısa matematik rutinleri.

0

Ayrıca, bir satır içi yöntem, büyük projeleri sürdürürken ciddi yan etkilere sahiptir. Satır içi kod değiştirildiğinde, bunu kullanan tüm dosyalar derleyici tarafından otomatik olarak yeniden oluşturulur (iyi bir derleyicidir). Bu, geliştirme sürenizin çoğunu boşa harcayabilir.

Bir inlineyöntem bir kaynak dosyaya aktarıldığında ve artık satır içine alınmadığında, tüm proje yeniden oluşturulmalıdır (en azından bu benim deneyimimdi). Ve ayrıca yöntemler satır içine dönüştürüldüğünde.


1
Bu farklı bir konu. Bir üstbilgi dosyasına yerleştirilen kod için yeniden oluşturma sorunu alırsınız. İşaretlenmiş inlineveya işaretlenmemiş olması önemli değildir ( inlineanahtar kelime olmadan, bağlayıcı hataları alırsınız - ancak inlineanahtar kelime aşırı yeniden oluşturmaya neden olan sorun değildir.
jalf

Ancak, bir satır içi yönteminin değiştirilmesi, bir kaynak dosyasında satır içi olmayan bir yöntemin değiştirilmesine karşı aşırı yapılara neden olur.
Thomas Matthews

0

Bir kullanmalıdır satır içi işlev kodu işlevleri bellek alanında tasarruf değerinde yürütme hızındaki nispeten küçük kurban olduğundan normal fonksiyonlarını tercih etmeliyiz büyüktür small.If olduğu zaman işlev eleme.


0

Kodunuzun satır içi olarak kullanılacak kadar küçük olduğunu düşündüğünüzde ve satır içi işlevini hatırlayın, kodunuzu çoğaltın ve yapıştırın, işlev çağrıldı, bu nedenle yürütme sürenizi artıracak kadar iyi olabilir, ancak bellek tüketimini de artırabilir. Bir döngü / statik değişken / özyinelemeli / switch / goto / Sanal işlevini kullanırken satır içi işlevi kullanamazsınız. Sanal, derleme sırasında çalışma zamanı ve satır içi araçların aynı anda kullanılamaması için beklemek anlamına gelir.


-2

Bazı cevapları okudum ve bazı şeyler eksik olduğunu görüyorum.

Kullandığım kural, satır içi olmasını istemedikçe satır içi kullanmak değildir. Aptalca görünüyor, şimdi açıklama.

Derleyiciler yeterince akıllıdır ve kısa fonksiyonlar her zaman satır içi yapar. Programcı bunu söylemedikçe asla satır içi işlevini uzun süre yerine getirmez.

Satır içi derleyiciye bir ipucu veya istek olduğunu biliyorum

Aslında inlinederleyici için bir emirdir, hiçbir seçeneği yoktur ve inlineanahtar kelime tüm kodu satır içinde yapar sonra . Böylece asla inlineanahtar kelime kullanamazsınız ve derleyici en kısa kodu tasarlar.

Peki ne zaman kullanılır inline?

Bazı kodların satır içi olmasını istiyorsanız kullanmak için. Sadece bir örnek biliyorum, çünkü sadece tek bir durumda kullanıyorum. Kullanıcı kimlik doğrulamasıdır.

Örneğin ben bu işlevi var:

inline bool ValidUser(const std::string& username, const std::string& password)
{
    //here it is quite long function
}

Bu fonksiyon ne kadar büyük olursa olsun, satır içi olarak kullanmak istiyorum çünkü yazılımımı kırmayı zorlaştırıyor.


3
satır içi hala bir ipucu. Derleyici, işlevinizin çok şişirilmiş olduğunu düşünürse satır içi yapamaz.
It'sPete

Biri satır içi bir emirdir ... diğeri bunun bir ipucu olduğunu söyler.

@ user2918461 i inline destek sadece bir ipucu olduğunu destekliyor. Bu, birçok web sitesi ve kitap tarafından desteklenmiştir
WARhead
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.