c++ - अनाम/अज्ञात नेमस्पेस बनाम स्थिर कार्य




namespaces (7)

अज्ञात नेमस्पेस और स्थिर कार्यों के बीच एक कंपाइलर विशिष्ट अंतर निम्नलिखित कोड को संकलित किया जा सकता है।

#include <iostream>

namespace
{
    void unreferenced()
    {
        std::cout << "Unreferenced";
    }

    void referenced()
    {
        std::cout << "Referenced";
    }
}

static void static_unreferenced()
{
    std::cout << "Unreferenced";
}

static void static_referenced()
{
    std::cout << "Referenced";
}

int main()
{
    referenced();
    static_referenced();
    return 0;
}

वीएस 2017 के साथ इस कोड को संकलित करना (चेतावनी सी 4505 को सक्षम करने के लिए स्तर 4 चेतावनी ध्वज / डब्ल्यू 4 निर्दिष्ट करना : असुरक्षित स्थानीय फ़ंक्शन हटा दिया गया है ) और जीसीसी 4.9--उन्यूज्ड-फ़ंक्शन या -वॉल ध्वज के साथ दिखाता है कि वीएस 2017 केवल चेतावनी उत्पन्न करेगा अप्रयुक्त स्थिर कार्य। जीसीसी 4.9 और उच्चतर, साथ ही क्लैंग 3.3 और उच्चतर, नामस्थान में असुरक्षित फ़ंक्शन के लिए चेतावनियां उत्पन्न करेंगे और अप्रयुक्त स्थिर फ़ंक्शन के लिए चेतावनी भी देंगे।

जीसीसी 4.9 और एमएसवीसी 2017 का लाइव डेमो

सी ++ की एक विशेषता अज्ञात (अनाम) नामस्थान बनाने की क्षमता है, जैसे:

namespace {
    int cannotAccessOutsideThisFile() { ... }
} // namespace

आपको लगता है कि ऐसी सुविधा बेकार होगी - चूंकि आप नामस्थान का नाम निर्दिष्ट नहीं कर सकते हैं, इसके बाहर से कुछ भी एक्सेस करना असंभव है। लेकिन इन अज्ञात नामस्थानों को उनके द्वारा बनाई गई फ़ाइल के भीतर पहुंच योग्य है, जैसे कि आपके पास इनका उपयोग करने के लिए एक अंतर्निहित था।

मेरा सवाल यह है कि स्थिर कार्यों का उपयोग करने के लिए यह कब या कब बेहतर होगा? या क्या वे अनिवार्य रूप से एक ही काम करने के दो तरीके हैं?


अज्ञात नेमस्पेस में विधियों को डालने से आपको एक परिभाषा नियम का गलती से उल्लंघन करने से रोकती है, जिससे आप अपने सहायक तरीके को नाम देने की चिंता करने की अनुमति नहीं देते हैं, जैसा कि आप लिंक कर सकते हैं।

और, जैसा कि ल्यूक द्वारा इंगित किया गया है, अज्ञात नामस्थानों को मानक सदस्यों द्वारा मानक द्वारा प्राथमिकता दी जाती है।


अपने प्रश्न को पढ़ने के दौरान केवल इस सुविधा के बारे में सीखा है, मैं केवल अनुमान लगा सकता हूं। ऐसा लगता है कि फ़ाइल-स्तर स्थिर चर पर कई फायदे उपलब्ध हैं:

  • बेनामी नामस्थान एक दूसरे के भीतर घोंसला जा सकता है, जिससे सुरक्षा के कई स्तर प्रदान किए जा सकते हैं जिससे प्रतीकों से बच नहीं सकते हैं।
  • कई अज्ञात नेमस्पेस को उसी स्रोत फ़ाइल में रखा जा सकता है, जो एक ही फ़ाइल में प्रभावी रूप से अलग-अलग स्थैतिक-स्तरीय स्कोप बनाते हैं।

मुझे सीखने में दिलचस्पी होगी अगर किसी ने असली कोड में अनाम नामस्थान का उपयोग किया है।


इसके अलावा यदि कोई इस चर की तरह एक चर पर स्थिर कीवर्ड का उपयोग करता है:

namespace {
   static int flag;
}

यह मैपिंग फ़ाइल में नहीं देखा जाएगा


एक किनारा मामला है जहां स्थैतिक आश्चर्यजनक प्रभाव डालता है (कम से कम यह मेरे लिए था)। 14.6.4.2/1 में सी ++ 03 मानक राज्य:

फ़ंक्शन कॉल के लिए जो टेम्पलेट पैरामीटर पर निर्भर करता है, यदि फ़ंक्शन नाम एक अयोग्य आईडी है लेकिन टेम्पलेट-आईडी नहीं है , तो उम्मीदवार फ़ंक्शंस सामान्य लुकअप नियम (3.4.1, 3.4.2) का उपयोग करके पाए जाते हैं, सिवाय इसके कि:

  • अयोग्य नाम लुकअप (3.4.1) का उपयोग करके लुकअप के हिस्से के लिए, टेम्पलेट परिभाषा संदर्भ से बाहरी लिंकेज के साथ केवल फ़ंक्शन घोषणाएं पाई जाती हैं।
  • संबंधित नेमस्पेस (3.4.2) का उपयोग करके लुकअप के हिस्से के लिए, टेम्पलेट परिभाषा संदर्भ या टेम्पलेट तत्काल संदर्भ में पाए गए बाहरी लिंकेज के साथ केवल फ़ंक्शन घोषणाएं मिलती हैं।

...

नीचे दिया गया कोड foo(void*) को कॉल करेगा और foo(S const &) जैसा कि आप उम्मीद कर सकते हैं।

template <typename T>
int b1 (T const & t)
{
  foo(t);
}

namespace NS
{
  namespace
  {
    struct S
    {
    public:
      operator void * () const;
    };

    void foo (void*);
    static void foo (S const &);   // Not considered 14.6.4.2(b1)
  }

}

void b2()
{
  NS::S s;
  b1 (s);
}

अपने आप में यह शायद एक बड़ा सौदा नहीं है, लेकिन यह इस बात को हाइलाइट करता है कि पूरी तरह से अनुपालन सी ++ कंपाइलर (यानी export लिए समर्थन वाला एक) के लिए static कीवर्ड में अभी भी कार्यक्षमता होगी जो किसी भी अन्य तरीके से उपलब्ध नहीं है।

// bar.h
export template <typename T>
int b1 (T const & t);

// bar.cc
#include "bar.h"
template <typename T>
int b1 (T const & t)
{
  foo(t);
}

// foo.cc
#include "bar.h"
namespace NS
{
  namespace
  {
    struct S
    {
    };

    void foo (S const & s);  // Will be found by different TU 'bar.cc'
  }
}

void b2()
{
  NS::S s;
  b1 (s);
}

यह सुनिश्चित करने का एकमात्र तरीका है कि हमारे नामित नेमस्पेस में फ़ंक्शन एडीएल का उपयोग करके टेम्पलेट्स में नहीं मिलेगा, यह static

आधुनिक सी ++ के लिए अद्यतन करें

सी ++ '11 के रूप में, एक अनाम नामस्थान के सदस्यों के पास आंतरिक संबंध अंतर्निहित है (3.5 / 4):

एक अनाम नामस्थान या एक नामांकित नामस्थान के भीतर प्रत्यक्ष या अप्रत्यक्ष रूप से घोषित नामस्थान में आंतरिक संबंध है।

लेकिन साथ ही, लिंक के उल्लेख को हटाने के लिए 14.6.4.2/1 अपडेट किया गया था (यह सी ++ '14 से लिया गया है):

फ़ंक्शन कॉल के लिए जहां पोस्टफिक्स-अभिव्यक्ति एक आश्रित नाम है, उम्मीदवार फ़ंक्शन सामान्य लुकअप नियम (3.4.1, 3.4.2) का उपयोग करके पाए जाते हैं, सिवाय इसके कि:

  • अयोग्य नाम लुकअप (3.4.1) का उपयोग करके लुकअप के हिस्से के लिए, केवल टेम्पलेट परिभाषा संदर्भ से कार्य घोषणाएं पाई जाती हैं।

  • संबंधित नेमस्पेस (3.4.2) का उपयोग करके लुकअप के हिस्से के लिए, केवल टेम्पलेट परिभाषा संदर्भ या टेम्पलेट तत्काल संदर्भ में पाए गए फ़ंक्शन घोषणाएं पाई जाती हैं।

नतीजा यह है कि स्थैतिक और अनामित नामस्थान सदस्यों के बीच यह विशेष अंतर मौजूद नहीं है।


मैंने हाल ही में अपने कोड में अज्ञात नेमस्पेस के साथ स्थैतिक कीवर्ड बदलना शुरू कर दिया लेकिन तुरंत एक समस्या में भाग गया जहां नामस्थान में चर मेरे डीबगर में निरीक्षण के लिए उपलब्ध नहीं थे। मैं वीसी 60 का उपयोग कर रहा था, इसलिए मुझे नहीं पता कि यह अन्य डिबगर्स के साथ एक गैर-मुद्दा है या नहीं। मेरा कामकाज एक 'मॉड्यूल' नामस्थान को परिभाषित करना था, जहां मैंने इसे अपनी सीपीपी फ़ाइल का नाम दिया था।

उदाहरण के लिए, मेरी XmlUtil.cpp फ़ाइल में, मैं अपने सभी मॉड्यूल चर और कार्यों के लिए नामस्थान XmlUtil_I {...} परिभाषित करता हूं। इस तरह मैं चरों तक पहुंचने के लिए डीबगर में XmlUtil_I :: योग्यता लागू कर सकता हूं। इस मामले में, '_I' इसे सार्वजनिक नामस्थान से अलग करता है जैसे XmlUtil कि मैं कहीं और उपयोग करना चाहूंगा।

मुझे लगता है कि वास्तव में अज्ञात की तुलना में इस दृष्टिकोण का संभावित नुकसान यह है कि कोई अन्य मॉड्यूल में नेमस्पेस क्वालीफायर का उपयोग कर वांछित स्थिर दायरे का उल्लंघन कर सकता है। मुझे नहीं पता कि यह एक प्रमुख चिंता है या नहीं।


सी ++ मानक खंड 7.3.1.1 में पढ़ता है अनाम नामस्थान, अनुच्छेद 2:

नामस्थान स्कोप में ऑब्जेक्ट्स घोषित करते समय स्थैतिक कीवर्ड का उपयोग बहिष्कृत किया जाता है, अनामित नामस्थान बेहतर विकल्प प्रदान करता है।

स्टेटिक केवल ऑब्जेक्ट्स, फ़ंक्शंस और अनाम यूनियनों के नाम पर लागू होता है, घोषणाओं को टाइप न करें।

संपादित करें:

स्थैतिक कीवर्ड (अनुवाद इकाई में एक परिवर्तनीय घोषणा की दृश्यता को प्रभावित करने) के इस उपयोग को समाप्त करने का निर्णय उलट दिया गया है ( ref )। इस मामले में एक स्थैतिक या एक अनाम नाम का उपयोग कर अनिवार्य रूप से एक ही चीज़ करने के दो तरीके होने के लिए वापस आ गए हैं। अधिक चर्चा के लिए कृपया this SO प्रश्न देखें।

अनाम नामों के पास अभी भी अनुवाद-इकाई-स्थानीय प्रकारों को परिभाषित करने की अनुमति देने का लाभ है। अधिक जानकारी के लिए कृपया this SO प्रश्न देखें।

मेरे ध्यान में लाने के लिए क्रेडिट माइक पर्सी जाता है।





namespaces