C ++ ile `using` kullanın veya bundan kaçının?


17

ADL nedeniyle farklı semantikleri indirim yapmak, genellikle nasıl kullanmalıyım usingve neden? Duruma bağlı mıdır (örneğin, #included'ye karşılık gelen başlık, kaynak dosyaya karşı değil)?

Ayrıca, ben tercih etmeliyiz ::std::yoksa std::?

  1. Ad alanı düzeyi using namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  2. Tamamen açık olmak:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
  3. Ad alanı düzeyinde kullanma bildirimleri:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
  4. İşlev-yerel kullanım-bildirimleri:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. Yerel işlev using namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. Başka bir şey?

Bu, C ++ 14 öncesi olduğu varsayılmaktadır ve dolayısıyla geri dönüş tipi kesinti kullanılmamaktadır auto.



@AProgrammer: Ah, bağlantım için teşekkürler, sorumun bir kısmını yanıtlıyor. :) Hala ::std::vs vs merak std::.
user541686

4
Sanırım stdikinci olmadan kullanıyorum . Bir std ad alanını tanımlayan biri sorun istiyor (ve muhtemelen çoğu insanın kullandığı stdve kullanmadığı avantajlardan yararlanmak için ::std).
AProgrammer

Yanıtlar:


25

usingBaşlıklarda kullanmaktan kaçının , çünkü bu ad alanlarının amacını bozar.

Kaynak dosyalarda kullanmak iyidir, ancak yine de bazı durumlarda (örneğin using std) bundan kaçınırım .

Ancak iç içe geçmiş ad alanlarınız varsa sorun değil:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1, kaç öğreticinin ve kolej dersinin using, ad alanlarının neden başlangıçta kullanıldığının tam bir açıklaması olmadan anahtar kelimeyi kullanmanız gerektiğini söylemesi şaşırtıcıdır .
Jeffrey Sweeney

İnsanlar iostreams, stringler vb. İle uğraşmak istiyorlar. Bir şey kullanmak istedikleri her seferinde std :: yazmak istemiyorlar ya da kodlarının önüne koymak için başka bir kazan plakasını hatırlamak zorunda değiller, bu da unuturlarsa yardımcı olmaktan daha az hataya neden olur. . :(
Colen

Typedef std :: string sstring gibi bir şey; alternatif olabilir mi?
Giorgio

1
@Colen: Bu zavallı ruhlar using std::coutve arkadaşları kullanabilir , ama coutzaten çok uzun bir isim gibi değil .
Benjamin Bannier

1
"İlk C ++ sınıfım" ın ilk gününde bir üniversite öğrencisiyseniz, bu anlamadığınız sözdizimi hatalarına neden olabilecek başka bir şeydir. Anlamak kolaydır, çünkü deneyimli programcılaryız, ancak dili öğrenmeye çalıştığınızda, ihtiyaç duymadığınız konusunda endişelenmeniz gereken başka bir şey.
Colen

11

Bir kaynak dosyaya using ifadesi koyarken, LÜTFEN, ihtiyacınız olan şeyleri çekin. Örneğin:

using std::string;
using std::ostringstream;

Buradaki sorun şudur:

using namespace std;

std den global isim alanına HER TEK ŞEY çekin. Bu, kodunuzda std'de tamamen bilmediğiniz bir adla yanlışlıkla bir ad kullandığınızda çok ilginç hata mesajlarına yol açar. Sadece istediğiniz şeyleri çekerseniz, o zaman bu problemi yaşamayacaksınız (veya daha doğrusu, kodunuz üzerinde çalışacak bir sonraki programcının bu sorunu olmayacaktır).


Alternatif olarak, using namespacesorundan kaçınarak sadece bir işlev kapsamında olabilirsiniz .
Tamás Szelei

2
@fish - aslında, işlev alanında 'ad alanını kullanma' yapmak sorunu engellemez, sadece işlerin yanlış gidebileceği alanı sınırlar. Ve sonuçta her fonksiyonda 'isim alanını kullanmak' varsa, bunu global olarak yapmaktan çok farklı değildir.
Michael Kohne

C ++ gerçekten işlev düzeyinde türleri bildirmesine izin verse de, bu yaygın bir şey değildir; bunun dışında, olası ad çakışmaları derleyici çıktısından kolayca tespit edilebilir (ancak bunun önlenmediği konusunda haklısınız).
Tamás Szelei

2

VJovic'in belirttiği gibi, usingbir başlık dosyasında kullanmayın . usingbaşlık dosyasında, geçerli derleme birimini (.cpp dosyası) kaynak dosyanın beklemeyeceği şekilde etkiler.

using namespacekaynak dosyada da kaçınılmalıdır. Bu, her sembolü kaynak dosyayla aynı kapsama getirir. Ad alanından belirli simgeler kullanırsanız okuyucularınıza ne yaptığınız daha açıktır.


2
Pratik bir endişe olarak, kodunuz yaygın olarak kullanılan adları geçersiz using namespace JoystickModulekılmazsa, bir .cpp dosyasının başlangıcında, JoystickModule::her nesneye ekliyorum.
Alex P

@AlexP: Ben de aynen böyle yapıyorum. usingŞu anda üzerinde çalıştığım kendi ad alanım için bir deyim var ve diğer her şey ad alanında kalıyor.
Benjamin Kloster

"İsim alanından belirli sembolleri kullan" konusuna dikkat etmeliyim. Her kullanımda okunabilirliğe yardımcı olmayan her simgeye önek eklemek yerine açık sembol kaldırma kullanmayı tercih ederim. using SomeNameSpace::SomeSymbol. Bu, ad alanındaki her sembolü geçerli kapsama taşımaktan kaçınır.
Bill Door

0

usingBaşlıklar içinde yazmak , hata ayıklamak için her türlü kötü ve imkansız oluşturmak için en iyi yoldur . Do not bunu.

using namespace XYZKaynak dosyaya yazmak biraz daha iyidir, ancak yine de sayısız baş ağrısına neden olabilir. Güvenli yol, ne kullandığınızı açıkça belirtmektir using Foo::Bar.

Diyelim ki aşağıdakilerle Bar.cpp var:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

İşlev bir güne kadar iyi çalıştı - görünüşte ilgili sınıflarda herhangi bir kod değişikliği olmadan - davranışı değişti: Aniden currentIndexher zaman bir tane kapalı gibi görünüyor . Son değişiklikleri incelediğinizde, kodla uzaktan bile ilgili bir değişiklik fark etmezsiniz.

Sonunda sebebini keşfedersiniz:
Siz (dolaylı olarak) bir Foo.hyere dahil edersiniz . Foo ad alanının dosyalarına yeni bir işlev eklendi:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

Hangi için unambigiously daha iyi bir eşleşme increment(int)sizin işlevinden daha increment(double)- yani şimdi Foo::increment()işlev tarafından çağrılan Bar::someFunction()yerine. Whoops.

(Ve içerme ağacınızın herhangi bir yerinde çok iyi olabilecek usingBaşlıklara yazarsanız ...)using namespace Foo

Yani ... Do not herhangi yazma usingBaşlıklardaki, ve de yazılı dikkatli olun using namespacekaynak dosyalarında.

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.