Adsız ad alanları neden kullanılır ve faydaları nelerdir?


242

Yeni bir C ++ yazılım projesine katıldım ve tasarımı anlamaya çalışıyorum. Proje, isimsiz ad alanlarını sıkça kullanmaktadır. Örneğin, bir sınıf tanımı dosyasında böyle bir şey olabilir:

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

Adsız bir ad alanı kullanmasına neden olabilecek tasarım konuları nelerdir? avantajları ve dezavantajları nelerdir?

Yanıtlar:


189

Adsız ad alanları, tanımlayıcı çeviri birimini yerel kılmak için bir yardımcı programdır. Bir ad alanı için çeviri birimi başına benzersiz bir ad seçer gibi davranırlar:

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

Boş gövdeyi kullanmanın ek adımı önemlidir, bu nedenle ::name, kullanım yönergesi zaten gerçekleştiğinden , ad alanı gövdesi içinde bu ad alanında tanımlanan tanımlayıcılara zaten başvurabilirsiniz .

Bu help, birden fazla çeviri biriminde bulunabilen (örneğin) adlı ücretsiz işlevlere sahip olabileceğiniz anlamına gelir ve bağlantı zamanında çakışmazlar. Etki, statictanımlayıcıların beyanına koyabileceğiniz C'de kullanılan anahtar kelimeyle neredeyse aynıdır . Adsız ad alanları, yerel bir çeviri birimi bile oluşturabilen üstün bir alternatiftir.

namespace { int a1; }
static int a2;

Her ikisi de ayerel çeviri birimidir ve bağlantı zamanında çakışmaz. Ancak fark, a1anonim ad alanındaki benzersiz bir ad almasıdır.

Comeau-computing adresindeki mükemmel makaleyi okuyun Neden statik yerine adsız bir ad alanı kullanılıyor? ( Archive.org aynası ).


İle ilişkisini açıklıyorsunuz static. Lütfen karşılaştırır __attribute__ ((visibility ("hidden")))mısınız?
phinz

74

Anonim bir ad alanında bir şeye sahip olmak, bu çeviri biriminde (.cpp dosyası ve tüm içerdiği) yerel olduğu anlamına gelir; bu, başka bir yerde aynı ada sahip başka bir sembol tanımlanırsa, Bir Tanımlama Kuralının ihlali olmayacağı anlamına gelir. (ODR) .

Bu, statik bir global değişkene veya statik fonksiyona sahip olmanın C yöntemiyle aynıdır, ancak sınıf tanımları için de kullanılabilir (ve staticC ++ yerine kullanılmalıdır ).

Aynı dosyadaki tüm anonim ad alanları aynı ad alanı olarak kabul edilir ve farklı dosyalardaki tüm anonim ad alanları farklıdır. Anonim bir ad alanı aşağıdakilere eşdeğerdir:

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;

14

Adsız ad alanı, sınıf, değişken, işlev ve nesnelerin tanımlandığı dosyaya erişimini sınırlar. Adsız ad alanı işlevselliği, staticC / C ++ 'daki anahtar kelimeye benzer .
staticanahtar kelime, genel değişkenin ve işlevin tanımlandıkları dosyaya erişimini sınırlar.
Adsız ad alanı ile staticanahtar kelime arasında fark vardır, çünkü adsız ad alanı statikten daha avantajlıdır. staticanahtar kelime değişken, işlev ve nesnelerle kullanılabilir ancak kullanıcı tanımlı sınıfla kullanılamaz.
Örneğin:

static int x;  // Correct 

Fakat,

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

Ama aynı isimsiz isim alanı ile mümkün olabilir. Örneğin,

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct

13

Bu soruya verilen diğer yanıtlara ek olarak, anonim bir ad alanı kullanmak da performansı artırabilir. Ad alanındaki semboller herhangi bir harici bağlantıya ihtiyaç duymadığından, derleyici, ad alanındaki kodun agresif optimizasyonunu gerçekleştirmek için daha özgürdür. Örneğin, bir döngüde birden çok kez çağrılan bir işlev, kod boyutu üzerinde herhangi bir etkisi olmadan satır içine alınabilir.

Örneğin, sistemimde, anonim ad alanı kullanılıyorsa, aşağıdaki kod çalışma süresinin yaklaşık% 70'ini alır (x86-64 gcc-4.6.3 ve -O2; add_val içindeki ekstra kodun derleyiciyi dahil etmek istemediğini unutmayın iki kez).

#include <iostream>

namespace {
  double a;
  void b(double x)
  {
    a -= x;
  }
  void add_val(double x)
  {
    a += x;
    if(x==0.01) b(0);
    if(x==0.02) b(0.6);
    if(x==0.03) b(-0.1);
    if(x==0.04) b(0.4);
  }
}

int main()
{
  a = 0;
  for(int i=0; i<1000000000; ++i)
    {
      add_val(i*1e-10);
    }
  std::cout << a << '\n';
  return 0;
}

5
Gerçek olamayacak kadar iyi - bu segmenti gcc 4-1-2'de, O3 optimizasyonunu kullanarak, ve ad alanı ifadesiyle ve olmadan - - Aynı zamanı aldım (-s3, -O3 ile ve -O3 ile 4sec)
Theo

2
Bu kod, derleyiciyi satır içi b ve add_val değerlerini main olarak kullanmamaya ikna etmeye çalışmak için kasıtlı olarak karmaşıktı. O3 optimizasyonu, bloat kodlama maliyetinden bağımsız olarak çok fazla satır içi kullanır. Bununla birlikte, O3'ün add_val değerini satır içi yapamayacağı muhtemel işlevler vardır. Add_val'ı daha karmaşık hale getirmeyi veya farklı durumlarda anadan birden çok kez çağırmayı deneyebilirsiniz.
xioxox

5
@Daniel: Neyi kaçırıyorum? okuduğunuz gibi, -O3kendisiyle karşılaştırdığınızı söylediniz , sonra 3'e 4 saniye "aynı zamanda" dediniz. bunların hiçbiri biraz mantıklı değil. gerçek açıklama olur şüpheli , ama nedir?
underscore_d

@underscore_d -O2 yanıt durumları -O3 yerine her iki durumda da kullanılmıştır. Farklı optimizasyon seviyeleri farklı davranabilir. Ayrıca, farklı derleyici sürümleri farklı davranabilir (cevap modası geçmiş olabilir, yani)
Paul Stelian

1
@PaulStelian Bunu biliyorum, ancak xioxox'un cevabına değil, Theo'nun yorumuna cevap verdiğimi oldukça açık görünüyor (ya adı değişti ya da bir şekilde
underscore_d

12

Örnek, katıldığınız projedeki kişilerin anonim ad alanlarını anlamadığını gösterir :)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

constNesne zaten statik bağlantıya sahip olduğundan ve bu nedenle muhtemelen başka bir çeviri biriminde aynı ada sahip tanımlayıcılarla çakışamayacağı için bunların anonim bir ad alanında olması gerekmez .

    bool getState(userType*,otherUserType*);
}

Ve bu aslında bir karamsarlık: getState()dış bağlantısı var. Sembol tablosunu kirletmediği için statik bağlantıyı tercih etmek genellikle daha iyidir. Yazmak daha iyidir

static bool getState(/*...*/);

buraya. Aynı tuzağa düştüm (standartta dosya istatistiklerinin anonim ad alanları lehine bir şekilde kullanımdan kaldırıldığını gösteren ifadeler var), ancak KDE gibi büyük bir C ++ projesinde çalışarak, başınızı doğru şekilde çeviren birçok insan var yine etrafında :)


10
C ++ 11 adsız ad alanları dahili bağlantıya sahip olduğundan (standartta bölüm 3.5 veya en.cppreference.com/w/cpp/language/namespace#Unnamed_namespaces bölüm 3.5 )
Emile Vrijdags

11
Ama yine de, onların semantik bir görsel hatırlatma olarak, birinde onları koymak ve (daha da) önemsiz kaldırmak için bunu yapmak için zarar vermez - Emin Teknik olarak, "Bunlar anonim ad alanında olması gerekmez" constlık daha sonra istenirse. Şüpheliyim ki OP takımı hiçbir şey "anlamıyor"! Ayrıca, harici bağlantıya sahip anonim ad alanlarındaki işlevlerle ilgili bit, C ++ 11'den sonra belirtildiği gibi yanlıştır. Anladığım kadarıyla, daha önce harici bağlantıya ihtiyaç duyan şablon argümanları sorununu çözdüler, bu nedenle adsız ad alanlarının (şablon argümanlarını içerebilen) dahili bağlantıya sahip olmasına izin verebilirler.
underscore_d

11

Anonim bir ad alanı, ekteki değişkenleri, işlevleri, sınıfları, vb. Örneğinizde bu, global değişkenlerden kaçınmanın bir yoludur. Çalışma zamanı veya derleme zamanı performans farkı yoktur.

"Bu değişkenin, fonksiyonun, sınıfın vs. genel veya özel olmasını ister miyim?" Dışında bir avantaj veya dezavantaj yoktur.


2
Performans farklılıkları olabilir - cevabımı buradan görebilirsiniz. Derleyicinin kodu daha iyi optimize etmesini sağlar.
xioxox

2
Haklısın; en azından bugün C ++ kadar. Bununla birlikte, C ++ 98 / C ++ 03, şablon argümanları olarak kullanılabilmek için harici bağlantıya ihtiyaç duydu. Anonim ad alanlarındaki şeyler şablon bağımsız değişkenleri olarak bulunduğundan, dosya dışından bunlara başvurmanın bir yolu olmasa bile, dış bağlantıya (en azından C ++ 11 öncesi) sahip olacaklardır. Bence bu konuda bazı yetenekler olabilir, çünkü standart sadece şeylerin kurallar uygulanmış gibi davranmasını gerektirir; ve bazen kuralları gerçekten zorlamadan bunu yapmak mümkündür.
Max Lybbert
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.