“Ad alanı kullanma” kirliliği nedir?


15

Google kodlama kılavuzuna [burada] bakıyordum ve bir using namespaceya da kullanmasını önermiyorlar namespace::function- eğer yanlış yorumlamazsam.

Bu da geçerli stdmi? cout<<onsuz çalışmaz. Bu kitap , aynı şeyi önerir. Peki veya cout<<olmadan nasıl kullanmaya devam edebilirim ?using namespace std;std::cout<<

Tavsiye edilen yol nedir? std::cout<<? Çoğu c ++ ders kitabı yeni başlayanlara using namespace std;kötü kodlama pratiği yayıyorlar mı?

Yanıtlar:


18

Google standardını okuduğum için, using namespace foo;yönergeyi hiçbir yerde kullanamazsınız . Bu yönerge isim alanında beyan edilen her şeyi getirir ve çarpışmaların ve beklenmedik davranışların ortak bir nedenidir. Diğerleri çok yaygın bir yöntem gösterdi: bir yerde kendi max veya min yönteminiz var ve birisinin yönteminizle bir başlık içerdiği ve daha sonra söylediği bir src dosyasında çarpışıyorusing namespace std;

Bazı yerlerde, formda olan bir kullanım bildirimi alınmasına izin verilir. using ::foo::bar;

İnsanlar kodlarında yönergeler kullanmayı sever, çünkü çok fazla yazım kazandırır, ancak riskle birlikte gelir. Çok fazla cout ifadesi olan bir dosyanız varsa, std :: cout'u yüz kez yazmak istemediğinizi anlayabilirim, ancak sadece :: std :: cout kullanarak söyleyebilirsiniz. Bunlara değişken beyanlar gibi davranıyorum: gerektiğinde onları kapsamla. 10 dosyadaki bir işlevin çıktı yazması gerekiyorsa, en üstteki cout yolunu bildirmeyin, gerçek çıktıyı yapan işleve koyun.

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

Bu sadece birkaç satırın çıktı yapmasıyla biraz aşırı, ama fikri anladınız.

Birinin yapabileceği başka bir şey, yazmayı en aza indirmek için takma ad veya typedef'tir. Ben bu kadar kötü ne olursa olsun std :: bulamıyorum, ama birkaç düzine modülleri ile kaynak büyük bir set var ve bazen gibi kod yazmak zorunda console_gui::command_window::append("text"). Bu bir süre sonra sıkıcı bir hal alır ve çok sayıda uzun çizgiye neden olur. Ben hep böyle bir şey için

typedef console_gui::command_window cw;
cw::append("text");

takma adlar yerel bir kapsamda yapıldıkça ve kodu okunabilir hale getirmek için yeterli bağlamda kaldığı sürece.


1
Teşekkürler! Bu gerçekten faydalı. Sadece güzel örneklerle neden kötü olduğunu açıklamakla kalmadınız, aynı zamanda güzel örneklerle çözümlere dikkat çektiniz. :-)
Lord Loh.

1
BTW: / std::endlüzerindeki açık yıkama için normalde oldukça gereksizdir, bu akışlar yine de / bağlıdır . Hatta işleri biraz yavaşlatır. stdoutstderrstdoutstderr
Tekilleştirici

8

Bunun nedeni: 1) isim çarpışmasını azaltmak olan ad alanlarının tüm amacını yener; 2) global ad boşluğuna using yönergesi ile belirtilen tüm isim boşluğunu sağlar.

Örneğin, kendi max () işlevinizi ekleyip tanımlarsanız, std :: max () ile çarpışır.

http://en.cppreference.com/w/cpp/algorithm/max

Hangi ad alanının kullanılacağını açıkça belirttiği için tercih std :: member_you_wish_to_use kullanmaktır.


Bunun std::max()alan adı öneki ile kullanmam gerektiği anlamına geldiğini düşünüyorum . Yoksa yanılıyor muyum?
Lord Loh.

3
Eğer "namespace std kullanarak;" kodunuzda, kendi maksimum işlevinizi (veya std ad alanında zaten tanımlanmış başka bir adı) tanımlarsanız hata alırsınız
Chewy Gumball

1
Bu sadece usingdirektiflere dikkat etmeniz gerektiği anlamına gelir, çünkü bu durumda bir tanesini tanımlayıp <algoritma> eklerseniz max () işlevinizi bozar. Bu basit bir durum ama ne kıracağınızı asla bilemezsiniz. Kütüphaneyi kırmadığınızdan emin olmak için tüm kütüphaneyi bilmeniz gerekir, ancak gelecekte kodunuzun kırılıp kırılmayacağını (yani ad çakışması) bilemezsiniz.
ApplePie

6

Sağladığınız bağlantıdan alıntı:

Kullanım bildirimini bir .cc dosyasında ve .h dosyalarındaki işlevlerde, yöntemlerde veya sınıflarda kullanabilirsiniz.

// .cc dosyalarında Tamam.

// .h dosyalarında bir işlev, yöntem veya sınıfta olmalıdır.

kullanma :: foo :: bar;

Google stili, global olarak ad alanlarını içe aktarmayı yasaklar, ancak yerel alanlarda bunu yapmanızı sağlar.

Beyannamenin kullanılmasının kodun sınırlı ve açıkça görülebilen bir kısmını etkilediği her yerde mükemmel bir şekilde kabul edilebilir.

Genel bağlamı kirlettiğinizde, ilişkisiz kod etkilenir (başlığınızın kullanılması nedeniyle). Yerel bağlamda bunu yaptığınızda hiçbir şey olmuyor.


Aynı standartlara sahibiz. Bazı insanlarımız yerel olarak uzun bir isim alanı tanımlayacaktır. örneğin typedef aptal :: barlicious fb; fb :: içecek d;
Michael Mathews

1

Bir isim alanı ornamespace: function` - kullanmasını önermezler - eğer yanlış yorumlamazsam.

Yaptın. Karşılıksızlık sadece using namespacedirektif için geçerlidir (bu abusing namespacetamamen mizahi olarak değil , yaygın olarak adlandırılır ). Gibi bir işlev veya nesnenin tam adını kullanmanız önemle tercih edilir std::cout.


1

Sorunun zaten faydalı cevapları olmasına rağmen, bir ayrıntı çok kısa görünüyor.

Çoğu programcı , referansı arayarak öğrenmeye çalışsa bile , usinganahtar kelime ve namespacekullanım açıklamaları ile biraz karıştırılır , çünkü beyan ve direktif biraz eşdeğer okur, her ikisi de d ile başlayan nispeten soyut uzun kelimelerdir .

Ad alanlarındaki tanımlayıcılara, ad alanını açıkça adlandırarak erişilebilir:

myNamespace::myIdent

bu yazmak için çok daha fazla anahtar olabilir. Ancak, çoğu tanımlayıcı aynı şekilde önek eklenirse, kodunuzun önemini de azaltabilir. usingAnahtar kelime bu ad olumsuz yanları önlemeye yardımcı olur. Yana usingderleyici seviyesinde (hiçbir makro var) eserlerin, etkisi ise kullanıldığı bütün kapsamı sürer. Bu, Google tarzı cpp dosyalarında başlık dosyaları veya fonksiyonlarda iyi tanımlanmış kapsamları, yani sınıflara kullanımını kısıtlar neden en.

... tabiki beyanı kullanmak arasında bir fark var

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

ve direktif kullanma

using myNamespace; // make all identifiers of myNamespace directly accessible

Büyük kapsamlarda kullanılırsa, ikincisi çok daha fazla karışıklığa yol açar .


1

Hadi bakalım:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

Bu şekilde yazarak, direktifleri ve bildirimleri kullanmakla birlikte hataya açık ADL'den kaçınırız.

Bu alaycı bir cevaptır. :-D

Bu konuda Google üzerinden Herb Sutter ile birlikteyim. C ++ Kodlama Standartlarından:

Sen ve edebilirsiniz gerektiğini bildirimleri kullanarak ad kullanmak ve direktifleri #include direktifleri ve bu konuda his iyi sonra uygulama dosyalarında liberal. Aksine ileri sürülen iddialara rağmen, bildirimleri ve direktifleri kullanan ad alanı kötü değildir ve ad alanlarının amacını bozmazlar. Bunun yerine, ad alanlarını kullanılabilir yapan şeydir .

Muhtemelen asla tezahür etmeyecek ve muhtemelen astronomik olarak nadir bir olayda usingdirektiflerden kaçınarak ve kullandığınız her şeyi (operatörlere kadar) usingbeyanlarla açıkça belirterek düzeltilmesi zor olmayacak potansiyel ad alanı çatışmalarına takıntı oluşturabilirsiniz veya sadece devam et ve başla using namespace std. İkincisini verimlilik açısından öneriyorum.

Çoğu c ++ ders kitabı yeni başlayanlara ad alanı std kullanarak öğretir; kötü kodlama pratiğini yayıyorlar mı?

Bana sorarsanız tam tersi ve yukarıdaki Sutter'in hemfikir olduğuna inanıyorum.

Kariyerim boyunca, usingon milyonlarca LOC'u kapsayan kod tabanlarındaki direktiflerin doğrudan bir sonucu olarak toplamda yaklaşık 3 isim alanı çatışmasıyla karşılaştım . Bununla birlikte, her üç durumda da, orijinal olarak C ile yazılan ve daha sonra C ++'a piç haline getirilen, bir düzine farklı kütüphaneden başlıklar da dahil olmak üzere büyük bir eklektik eklektik liste gerçekleştiren ve bir #includessayfaya yayılmış olan destansı bir liste . Destansı karışıklığa rağmen, çalışma zamanı hataları değil, OSX'te (kodun oluşturulamadığı bir işletim sistemi) derleme hatalarına neden oldukları için düzeltilmesi çok zor değildi. Kodunuzu bu kabus gibi düzenlemeyin ve iyi olmalısınız.

Bununla birlikte, başlık dosyalarında hem using yönergelerden hem de bildirimlerden kaçının . Bu sadece düzensiz. Ancak kaynak dosyalar ve özellikle #includedirektiflerle dolu bir sayfanın bulunmadığı dosyalar için, Google için çalışmıyorsanız terlemeyin.

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.