5.2.31 · D4 · HinglishC++ Programming

ExercisesInline namespaces, anonymous namespaces

2,586 words12 min read↑ Read in English

5.2.31 · D4 · Coding › C++ Programming › Inline namespaces, anonymous namespaces

Do words jo hum baar baar use karenge, ek baar define kar lete hain taaki koi symbol unexplained na rahe:


Level 1 — Recognition

Exercise 1.1

Anonymous namespace ke andar ke names ki linkage kya hoti hai?

Recall Solution

Internal linkage. Ek unnamed namespace mein declare kiya gaya har naam sirf us TU mein visible hota hai jisne use declare kiya. Compiler aise behave karta hai jaise usne har TU ke liye ek unique hidden naam banaya ho plus ek implicit using directive, isliye do alag .cpp files kabhi ek doosre ki copies nahi dekh saktin.

Exercise 1.2

Neeche diye code mein, kaun sa ek word process ko lib::process() ke roop mein reachable banata hai?

namespace lib {
    inline namespace v2 { void process(); }
}
Recall Solution

Keyword ==inline==. Kyunki v2 ek inline namespace hai, iske members enclosing namespace lib mein leak ho jaate hain, isliye lib::process() resolve hokar lib::v2::process() ban jaata hai.

Exercise 1.3

True ya false: anonymous namespace ek header file ke andar kuch declare karne ke liye acha jagah hai.

Recall Solution

False. Ek header kaafi TUs mein #include hoti hai; har inclusion ek alag internal-linkage copy produce karta hai. Concrete nuksan ke liye Exercise 2.2 dekho.


Level 2 — Application

Exercise 2.1

Do files mein se har ek ek file-local helper define karti hai. Kya ye link hoga?

// a.cpp
namespace { int compute() { return 1; } }
// b.cpp
namespace { int compute() { return 2; } }
Recall Solution

Haan, ye cleanly link hoga. Har compute ek alag invented unnamed namespace mein baitha hai (ek per TU), isliye linker do distinct symbols dekhta hai — koi clash nahi, One Definition Rule ka koi violation nahi. Agar dono global int compute() external linkage ke saath likhe hote, to linker "multiple definition of compute" report karta.

Exercise 2.2

Tumne namespace { int counter = 0; } util.h mein rakha aur use teen .cpp files mein include kiya, ek shared counter ki umeed mein. Asal mein kitne independent counter objects exist karte hain, aur kyun?

Recall Solution

Teen independent objects — ek per including TU. Unnamed namespace internal linkage force karta hai, aur internal linkage ka matlab hai har TU ko apni private copy milti hai. Ek file mein counter increment karna doosron ko affect nahi karta, aur binary teeno alag variables carry karta hai. Fix: shared counter ko external linkage ke saath rakho — header mein extern int counter; declare karo aur exactly ek .cpp mein define karo.

Exercise 2.3

Neeche diye versioned library mein, har call kahan resolve hogi?

namespace mathx {
    namespace v1 { double area(double r){ return 3.14 * r * r; } }
    inline namespace v2 { double area(double r){ return 3.14159 * r * r; } }
}
double a = mathx::area(2.0);
double b = mathx::v1::area(2.0);
Recall Solution
  • mathx::area(2.0)inline v2 version, kyunki v2 mathx mein leak ho jaata hai. Value: .
  • mathx::v1::area(2.0) → explicit legacy v1. Value: . Default callers free mein v2 par float karte hain; jo v1 pin karke bethe hain wo untouched rehte hain.
Figure — Inline namespaces, anonymous namespaces

Level 3 — Analysis

Exercise 3.1

Explain karo, us cheez ke terms mein jo compiler conceptually insert karta hai, kyun ek unnamed namespace kabhi files ke across collide nahi kar sakta, jabki ek global naam kar sakta hai.

Recall Solution

Har TU ke liye compiler aise act karta hai jaise usne likha:

namespace __unique_per_TU {  /* your names */  }
using namespace __unique_per_TU;   // implicit

Invented naam __unique_per_TU har .cpp mein alag hota hai. Isliye file A mein secret actually __uniqueA::secret hai aur file B mein __uniqueB::secret — alag fully-qualified names ⇒ alag linker symbols ⇒ koi collision nahi. Ek global naam ki ek shared fully-qualified spelling hoti hai aur external linkage hota hai, isliye do definitions ek hi symbol pe map hoti hain aur linker duplicate reject kar deta hai.

Exercise 3.2

Kya neeche unqualified draw(w) compile hoga? Argument-Dependent Lookup (ADL) use karke justify karo.

namespace ns {
    inline namespace impl { struct Widget {}; void draw(Widget){} }
}
ns::Widget w;
draw(w);   // no ns:: prefix
Recall Solution

Haan. ADL kehta hai: ek unqualified function call resolve karne ke liye, argument types se associated namespaces bhi search karo. Widget ka associated namespace ns::impl hai. Kyunki impl inline hai, iske contents ns ke members maane jaate hain, isliye associated set effectively ns ko include karta hai, aur draw (jo impl/ns mein rehta hai) mil jaata hai. Agar impl ek plain (non-inline) namespace hota, to draw ADL ke through phir bhi milta kyunki wo Widget ke saath usi associated namespace mein hai — inline keyword ka asli fayda tab dikhta hai jab tum ns::draw(w) qualified call karo, jo sirf isliye kaam karta hai kyunki inline draw ko ns mein leak karta hai.

Exercise 3.3

Kyun inline keyword ko v2 se v3 par move karna source-level calls aur linker symbols dono ko sahi se re-route karta hai, bina caller code ko touch kiye?

Recall Solution

Do layers ek saath change hoti hain:

  1. Source resolution: unqualified naam mathx::area ab jis bhi namespace mein inline hai wahan se leak hota hai. inline ko v3 par move karo aur har mathx::area call recompile hokar v3::area ban jaati hai — ek keyword diff, koi caller edits nahi.
  2. Linker symbols (ABI): inline namespace naam mangled symbol mein bake ho jaata hai, jaise _ZN5mathx2v34areaEd vs _ZN5mathx2v24areaEd. Isliye ek purani object file jo v2 ke against compile hui thi, v2 symbol ko reference karti rehti hai; wo silently v3 call nahi karne lagti. Version end-to-end encoded hai.

Level 4 — Synthesis

Exercise 4.1

Ek library net design karo jo experimental v3 ship kare jabki v2 default rahe, aur stable v1 callable rahe. Namespace skeleton likho aur batao in mein se har ek kahan resolve hoga: net::send(), net::v3::send(), net::v1::send().

Recall Solution
namespace net {
    namespace v1 { void send(); }          // legacy, opt-in
    inline namespace v2 { void send(); }    // current DEFAULT
    namespace v3 { void send(); }          // experimental, opt-in
}
  • net::send()net::v2::send() (sirf v2 inline hai, isliye sirf wahi leak karta hai).
  • net::v3::send() → experimental version, sirf explicit qualification se reachable.
  • net::v1::send() → legacy version, explicit. Jab v3 default banne ke liye ready ho to inline ko v2 se v3 par move karo; existing net::send() calls recompile par migrate ho jaati hain, v1/v2 ke pinned callers unaffected rehte hain.

Exercise 4.2

Tumhare paas ek header-based, single-file library hai jahan har symbol host program se clash avoid karne ke liye file-local hona chahiye, including ek helper struct Node. Explain karo kyun tum Node ke liye static use nahi kar sakte, aur sahi construct likho.

Recall Solution

static internal linkage sirf variables aur functions ko deta hai; ek type jaise struct Node ki is sense mein koi linkage nahi hoti jise static kiya ja sake — keyword simply class ko internal linkage dene ke liye allowed nahi hai. Uniform tool unnamed namespace hai, jo har cheez ko internal linkage deta hai, types bhi:

// helper.cpp   (NOT a header — anonymous namespaces stay in .cpp)
namespace {
    struct Node { int value; };
    Node makeNode(int v) { return Node{v}; }
}

Level 5 — Mastery

Exercise 5.1

Ek team namespace { int cache; } ek widely-included header mein likhti hai aur do symptoms report karti hai: (a) executable unexpectedly bada hai, aur (b) ek file mein cache pe writes doosri file mein invisible hain. Dono symptoms ko ek single root cause se diagnose karo, phir corrected design do.

Recall Solution

Root cause: internal linkage × N inclusions. Unnamed namespace cache ko internal-linkage banata hai, aur header, maan lo, N = 5 TUs include karte hain. Result: 5 independent cache objects.

  • Symptom (a), bloat: 5 alag variables (aur us namespace ke koi bhi functions) emit hote hain, ek per TU.
  • Symptom (b), no sharing: har TU apni khud ki copy read/write karta hai, isliye cross-file communication silently fail ho jaati hai. Corrected design — external linkage ke saath ek shared object:
// cache.h
extern int cache;          // declaration only
// cache.cpp
int cache = 0;             // single definition, external linkage

Ab exactly ek cache exist karta hai aur saare TUs use share karte hain. Rule of thumb: anonymous namespaces .cpp files mein rehte hain; shared state extern declaration + ek definition ke peeche rehti hai.

Exercise 5.2

Printed output predict karo. Phir explain karo ki kaun si mechanism (inline leak, ADL, ya per-TU uniqueness) har line exercise karti hai.

namespace app {
    namespace v1 { int scale(int x){ return x * 2; } }
    inline namespace v2 { int scale(int x){ return x * 10; } }
    inline namespace v2 { struct Vec { int n; }; int norm(Vec v){ return v.n; } }
}
int main() {
    app::Vec v{7};
    std::cout << app::scale(3)     << "\n";   // line A
    std::cout << app::v1::scale(3) << "\n";   // line B
    std::cout << norm(v)           << "\n";   // line C  (no app::)
}
Recall Solution

Output:

30
6
7
  • Line A → 30. app::scale inline leak ke through v2::scale par resolve hota hai, isliye .
  • Line B → 6. Explicit app::v1::scale legacy mein opt-in karta hai: .
  • Line C → 7. norm(v) unqualified hai. Vec ka associated namespace app::v2 hai, jo inline hai (isliye app bhi); ADL norm dhundhta hai. Ye v.n = 7 return karta hai.

Recall Master checklist

Anonymous namespace kaun si linkage deta hai? ::: Internal — per-TU private. Anonymous namespaces kabhi nahi aane chahiye? ::: Headers mein (har include = ek alag copy). inline namespace v2 ke saath lib::process() kahan resolve hota hai? ::: lib::v2::process(). Naya default version promote karne ke liye kaun sa keyword move karte hain? ::: inline. Kya inline namespace naam mangled symbol mein jaata hai? ::: Haan — ye ABI-tagged hota hai. Kya static kisi struct ko internal linkage de sakta hai? ::: Nahi; iske bajaye unnamed namespace use karo.