2015-04-17 32 views
25

içinde yıkanmasıyla ilgili sonuçları ve artıları/eksileri Son zamanlarda, endlendl akışını da temizlediğinden \n'unkullanılmasının tercih edildiğini belirten bir makaleyi okudum.
Ama konuyla ilgili biraz daha fazla bilgi için baktığımda belirtti bir site buldum: Eğer belleğe alma kaçınmak zorunda bir durumda iseAkışın C++

, std :: endl yerine kullanabilirsiniz ' \ n'

Şimdi burada sorumu gelir: hangi durumda o tampon yazmak için değil tercih edilir? Çünkü sadece bu tekniğin avantajlarını gördüm. Tampona yazmak da daha güvenli değil mi? Sabit sürücüden daha küçük olduğu için, HD'de depolanan verilere göre daha hızlı yazılır (bunun doğru olup olmadığından emin değilim). Eğer akışı kapatılmadan önce veri almak için Akışınızın hedef gerekiyorsa

+1

Arabelleğe alma kullanıldığında, kullanıcıdan bilgi istemeden (bir istemle) ve klavyeden okumadan önce metnin yazdırılmadığı bir iletişim kutusu yapmanız mümkündür. Bazı çevre birimleri (örneğin, seri port) durumunda, arabelleğe yazabilir ve program durduğunda, çevre birimi de kapatılabilir (ve veriler gönderilmez. – jcoppens

cevap

18

Arabelleğe alma gerçekleştiğinde, bir floş oluşmadan önce verilerin hemen alınacağına dair hiçbir garantiniz olmayacaktır. . Belirli koşullar altında, yanlış çıkış siparişi ve/veya bilgi/hata ayıklama verisi kaybı yaşayabilirsiniz, örn.

int main() { 

    std::cout << "This text is quite nice and might as well be buffered"; 
    raise(SIGSEGV); // Oh dear.. segmentation violation 
    std::cout << std::endl; 
} 

Live Example

Çıktı:

bash: line 7: 22235 Segmentation fault  (core dumped) ./a.out 

yukarıda arabelleğe beri herhangi bir metin sağ çıktı engelledi baskı görüntülenecek olmayacaktır. sadece bu tamponun sonunda bir kızarma std::endl eklerseniz Şimdi

ne olsun

int main() { 

    std::cout << "This text is quite nice and might as well be buffered" << std::endl; 
    raise(SIGSEGV); // Oh dear.. segmentation violation 
    std::cout << std::endl; 
} 

Live Example

Çıktı: Çıktı

This text is quite nice and might as well be buffered 
bash: line 7: 22444 Segmentation fault  (core dumped) ./a.out 

Bu kez progra'dan önce görünür. m sonlandırma. Bu gerçeğin etkileri çeşitlidir. Tamamen spekülatif: Veriler bir sunucu günlüğü ile ilgiliyse, uygulamanız gerçek günlüğe kaydetmeden önce kilitlenebilir.

10

tampon temizlemek tercih edilir.

Gerçek hayattaki bir örnek, her zaman açık olan bir akıştan yazılmış bir uygulama günlüğü olurdu ... Program hala çalışırken bu günlüğe bakmak isteyebilirsiniz.

12

Çıktının tam olarak görünmesi gerektiğinde tam olarak görünmesini istediğiniz herhangi bir durumda tercih edilecektir.

Basit bir örnek: Kullanıcı onun/onun adını yazın bekleniyor önce arabelleğe ile

#include <iostream> 
int main() { 
    std::cout << "Please enter your name: " << std::endl; 
    std::string name; 
    std::cin >> name; 
    ... 
} 

, metin kullanıcı karıştı olacak, böylece ekranda belirecektir. (Bu örnekte, C++, std::cin'dan herhangi bir girişten önce std::cout'u temizlemek için özel önlemler alabildiğinden, bu örneğin tam olarak etkinleştirilmiş olarak çalıştırmayı gerçekten zor veya imkansız olabilir, ancak bkz. Why do we need to tie std::cin and std::cout?. Ancak bu, yalnızca bir kuramsal örnektir. arabelleğe alma tam olarak etkinleştirilmiş, tam olarak etkin, kullanıcı istem görmez.)

Böyle bir durum zaman zaman oluşabilir, ancak çok sık olmayabilir. Başka bir süreçle etkileşime geçmek için bir boruya yazmayı düşünün. Ya da programınız günlük dosyasına yazıyorsa ve siz kişisel olarak zaman zaman nasıl çalıştığını görmek için günlük dosyasına bakarsanız --- arabelleğe alma durumunda, genellikle programdan yazdırılan çıktıyı görmezsiniz, ancak henüz tamponda kalıyor.

Hesabınız için önemli olan başka bir durum --- eğer programınız ciddi şekilde çökerse, arabellek içeriği sabit diskte hiç bitmeyebilir. (Akış yıkıcılarının arabelleği temizlemesini beklerim, ancak bir çarpışma o kadar şiddetli olabilir ki hiç bir yıkıcı hiç çağrılmayacaktır.)

+0

@Petr arabelleğe yazmanın daha güvenli ve daha sonra HD'ye – TheJavaFan

+0

@ TheJavaFan'a ne yazdığını, ne kadar "güvenli" olduğunu kastediyorsun ve neden böyle olduğunu düşünüyorsun? Neden daha güvenli olabileceğine dair bir sebep göremiyorum. Bu sizin de sorunuzda, ama aynı zamanda sorunuzun son cümlesini de tam olarak almıyorum.) – Petr

+0

@Petr Sadece tamponda verinin daha hızlı yazıldığını merak ediyordum. HD – TheJavaFan

10

İlk olarak, biraz revizyonist geçmiş. Herkesin I yapmak stdio.h kütüphane kullanılan Eskiden

, G/Ç, etkileşimli görüntülendi metin satır tamponlu tipik oldu (veya hatta tamponsuz) ve tam tamponlu edildi değildi metni. Bu nedenle, '\n' akışına çıktıysanız, "Her zaman" Doğru Şeyi yapar: satırlar temizlendi ve hemen göründü ve satırlar en yüksek performans için arabelleğe alınıyor. Ne yazık ki, aslında her zaman Doğru Şey değildir; Çalışma zamanı, kullanıcıların programınızın çıktısını gerçekte nasıl görmek istediklerini her zaman tahmin edemez. Yaygın bir tuzak, STDOUT'u yeniden yönlendiriyor - insanlar konsolda programlarını çalıştırıyor ve konsolu (çıktıdaki çizgi tamponlu davranışı ile) görüyorlar ve daha sonra nedense (örneğin, uzun süren iş) STDOUT yönünü yeniden yönlendirmeye karar verdiler bir dosyaya, ve çıktı artık satır-tamponlu olduğu gerçeğini hemen şaşırttı.

Bu sebepten ötürü haftalarca zaman harcanan süperbilgisayar zamanını gördüm; Çıktı, arabelleğin, işin nasıl ilerlediğini anlayabilmesini engelleyebilecek kadar sık ​​değildi. Bununla birlikte, C++ 'nun iostream kütüphanesi, numarasını Doğru Şey yapmak için tasarlanmıştır. stdio ile senkronize olmanın dışında, bu "belki de tamponlu belki de tam tamponlu" bir şey yapmaz. Bu her zaman tam arabelleğe alma kullanır (elbette, arabelleğe alınmamış şeyler yaptığınız zamanlar hariç) ve yeni satır öğelerini temizlemeyi isterseniz, bunu açıkça yaparsınız.

Bu nedenle, bir grup biçimlendirilmiş metni, işiniz bitene kadar bakmayacağı bir dosyaya döküyorsanız, satır sonları için \n yazarsınız.aslında bunu yazıyoruz süre bakmak isteyebilirsiniz metin insanları yazıyorsanız

Ancak sizin de satır sonları için std::endl kullanın ve hemen görüntülenen alır. Aynı anda birkaç satır yazıyorsanız, daha da iyisini yapabilirsiniz: Ara satır sonları için '\n' ve sonuncu için std::endl kullanın (veya '\n' ve std::flush). Bu ayarda performans genellikle önemli olmamasına rağmen, tüm satır sonları için yalnızca std::endl'u kullanmak iyidir.

+1

Sadece bir not: _line-buffered_ durumunda bile, çıktı her zaman _immediately_ görünmeyecek, sadece ilk yeni satırdan sonra görünecektir. Eğer her şeyi bir satırda veriyorsanız, çıktı etkin bir şekilde tam olarak tamponlanacaktır. Çıktının gerçekten _immediately_ görünmesini sağlamak için, her çıktıdan sonra açıkça 'flush()' işlevini çağırmanız gerekir. – Petr

5

Umarız bulduğunuz sitenin bağlantısını kaybettiniz. std::endl, arabelleklemeden kaçınıyor. Tampondaki her şeyi temizler. Tamponlamadan kaçınmanız gerekiyorsa, setf(ios_base::unitbuf)'u kullanın. Bu, her ekleme işleminden sonra akışın temizlenmesini ayarlar. Bu, std::clog için varsayılan ayardır. Bunu yapmanın nedeni, arabellekte tutulan daha az şey olması, program çöktüğü zaman kritik verilerinin akışa yazılma şansının o kadar yüksek olmasıdır.

Flushing da interaktif programlar için önemlidir: Eğer std::cout için bir istem yazarsanız programı girişi için bekleyen başlamadan önce bu istemi ekranında gelirse, bu iyi bir şeydir. Senkronizasyon ayarlarıyla uğraşmadıkça, std::cout ve std::cin'u kullandığınızda otomatik olarak yapılır.

Birçok programcı,'u '\n' yazımının süslü bir yolu olarak kullanıyor gibi görünüyor, ancak değil. Bir şey yazdığınızda her zaman çıktı tamponunu yıkamanıza gerek yoktur. OS ve standart kütüphane işlerini yapsınlar; Çıktının uygun bir zamanda zamanında alınmasına özen gösterirler. Basit bir std::cout << '\n';, çıktıya yeni bir çizgi koymak için gerekli olan ve er ya da geç, ekranda görünecek. Şimdilik göstermeniz gerekiyorsa, normalde şu an için tüm çıkışı yazdığınız ve görüntülenen bilgileri eksik bırakmak istemediğinizden, çıktının son satırından sonra std::endl kullanın.