مساحات الأسماء غير المسماة/المجهولة مقابل مساحات الأسماء غير المسماة/المجهولةوظائف ثابتة

StackOverflow https://stackoverflow.com/questions/154469

  •  03-07-2019
  •  | 
  •  

سؤال

إحدى ميزات لغة C++ هي القدرة على إنشاء مساحات أسماء غير مسماة (مجهولة)، كما يلي:

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

قد تعتقد أن مثل هذه الميزة ستكون عديمة الفائدة - نظرًا لأنه لا يمكنك تحديد اسم مساحة الاسم، فمن المستحيل الوصول إلى أي شيء بداخلها من الخارج.ولكن هذه مساحات الأسماء غير المسماة نكون يمكن الوصول إليها من خلال الملف الذي تم إنشاؤها فيه، كما لو كان لديك شرط استخدام ضمني لها.

سؤالي هو، لماذا أو متى يكون ذلك أفضل من استخدام الوظائف الثابتة؟أم أنهما في الأساس طريقتان لفعل نفس الشيء بالضبط؟

هل كانت مفيدة؟

المحلول

يقرأ معيار C++ في القسم 7.3.1.1 مساحات الأسماء غير المسماة، الفقرة 2:

يتم إهمال استخدام الكلمة الرئيسية الثابتة عند إعلان الكائنات في نطاق مساحة الاسم ، ويوفر مساحة الاسم غير المسماة بديلاً متفوقًا.

ينطبق الثابت فقط على أسماء الكائنات والوظائف والاتحادات المجهولة، وليس لكتابة الإعلانات.

يحرر:

تم التراجع عن قرار إهمال هذا الاستخدام للكلمة الأساسية الثابتة (يؤثر على رؤية إعلان المتغير في وحدة الترجمة) (المرجع).في هذه الحالة، يعود استخدام مساحة اسم ثابتة أو غير مسماة إلى كونها طريقتين أساسيتين للقيام بنفس الشيء تمامًا.لمزيد من المناقشة يرجى الاطلاع هذا هذا سؤال.

لا تزال مساحات الأسماء غير المسماة تتمتع بميزة السماح لك بتعريف أنواع وحدة الترجمة المحلية.لطفا أنظر هذا سؤال SO لمزيد من التفاصيل.

يذهب الائتمان إلى مايك بيرسي لجلب انتباهي إلى هذا.

نصائح أخرى

ووضع أساليب في مساحة الاسم مجهول يمنعك من انتهاك بطريق الخطأ href="http://en.wikipedia.org/wiki/One_Definition_Rule" واحدة تعريف القاعدة ، مما يسمح لك لتقلق أبدا تسمية أساليب مساعدك نفس بعض الطرق الأخرى التي قد تصل في.

و، كما أشار لوقا، ويفضل مساحات مجهولة وفق المعايير على أعضاء ثابتة.

هناك حالة واحدة حيث يكون للثبات تأثير مفاجئ (على الأقل بالنسبة لي).ينص معيار C++03 في 14.6.4.2/1:

بالنسبة لاستدعاء دالة يعتمد على معلمة قالب، إذا كان اسم الوظيفة هو معرف غير مؤهل ولكن ليس أ معرف القالب, ، تم العثور على الوظائف المرشحة باستخدام قواعد البحث المعتادة (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);
}

ربما لا يكون هذا في حد ذاته أمرًا كبيرًا، ولكنه يسلط الضوء على ذلك بالنسبة لمترجم C++ المتوافق تمامًا (أي:واحد مع دعم ل 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);
}

الطريقة الوحيدة لضمان عدم العثور على الوظيفة الموجودة في مساحة الاسم غير المسماة في القوالب التي تستخدم ADL هي جعلها static.

تحديث لC++ الحديثة

اعتبارًا من C++ '11، يكون لأعضاء مساحة الاسم غير المسماة رابط داخلي ضمنيًا (3.5/4):

مساحة الاسم غير المسماة أو مساحة الاسم المعلنة بشكل مباشر أو غير مباشر داخل مساحة اسم غير مسماة لها ارتباط داخلي.

ولكن في الوقت نفسه، تم تحديث 14.6.4.2/1 لإزالة ذكر الارتباط (هذا مأخوذ من C++ '14):

للحصول على استدعاء وظيفة حيث يكون التعبير postfix هو اسم تابع ، يتم العثور على وظائف المرشح باستخدام قواعد البحث المعتادة (3.4.1 ، 3.4.2) باستثناء:

  • بالنسبة لجزء البحث الذي يستخدم البحث عن اسم غير مؤهل (3.4.1)، تم العثور على إعلانات الوظائف فقط من سياق تعريف القالب.

  • بالنسبة لجزء البحث الذي يستخدم مساحات الأسماء المقترنة (3.4.2)، تم العثور على إعلانات الوظائف فقط الموجودة في سياق تعريف القالب أو سياق إنشاء مثيل القالب.

والنتيجة هي أن هذا الاختلاف المحدد بين أعضاء مساحة الاسم الثابتة وغير المسماة لم يعد موجودًا.

وأنا في الآونة الأخيرة بدأت على الفور باستبدال كلمات ثابتة مع مساحات مجهولة في قانون بلدي ولكن ركض على الفور إلى مشكلة حيث كانت المتغيرات في مساحة الاسم لم تعد متوفرة للتفتيش في بلدي المصحح. كنت تستخدم VC60، لذلك أنا لا أعرف إذا كان هذا هو غير مسألة مع مصححات أخرى. كان لي مشكلة لتحديد "وحدة" مساحة، حيث أعطيته اسم ملف حزب الشعب الكمبودي بلدي.

وعلى سبيل المثال، في ملف XmlUtil.cpp بلدي، وأنا تحديد XmlUtil_I مساحة الاسم {...} لجميع من بلدي المتغيرات وحدة ووظائفها. وبهذه الطريقة يمكنني تطبيق XmlUtil_I :: التأهيل في المصحح للوصول إلى المتغيرات. في هذه الحالة، "_I 'يميزها عن مساحة اسم عام مثل XmlUtil أنني قد ترغب في استخدام أي مكان آخر.

وأفترض عيب محتمل لهذا النهج بالمقارنة مع واحد مجهول حقا هو أن شخصا ما يمكن أن تنتهك نطاق ثابت المطلوبة باستخدام تصفيات مساحة في وحدات أخرى. أنا لا أعرف إذا كان هذا هو مصدر قلق كبير بالرغم من ذلك.

وتم إهمال استخدام الكلمة الأساسية ثابتة لهذا الغرض وفق المعايير C ++ 98. المشكلة مع ساكنة هو أنه لا ينطبق على كتابة تعريف. كما انها الكلمة طاقتها تستخدم بطرق مختلفة في سياقات مختلفة، لذلك بمساحات لم تسمها تبسيط الأمور قليلا.

ومن تجربة أنا مجرد ملاحظة أنه في حين أن هذه هي الطريقة C ++ لوضع وظائف ثابتة سابقا في مساحة الاسم مجهول، المجمعين كبار السن يمكن أن يكون في بعض الأحيان مشاكل مع هذا. أعمل حاليا مع عدد قليل من المجمعين لمنصات هدفنا، ومترجم لينكس أكثر حداثة على ما يرام مع وضع الوظائف في مساحة الاسم المجهول.

ولكن مترجم السن يعمل على سولاريس، والتي تزوج علينا حتى في إصدار مستقبلي غير محدد، لن يقبل أحيانا، وأحيانا أخرى العلم أنها خطأ. الخطأ ليس ما يقلقني، وهذا ما عليه <م> قد أن تفعل عندما <م> يقبل عليه. لذلك حتى نذهب عصري في جميع المجالات، ونحن لا تزال تستخدم ثابت (عادة الطبقة بنطاق) وظائف حيث نفضل مساحة الاسم المجهول.

وبالإضافة إلى ذلك إذا كان أحد يستخدم الكلمة الأساسية ثابتة على متغير مثل هذا المثال:

namespace {
   static int flag;
}

ولن ينظر إليه في ملف التعيين

بعد أن علمت بهذه الميزة للتو أثناء قراءة سؤالك، لا يسعني إلا أن أتكهن.يبدو أن هذا يوفر العديد من المزايا مقارنة بالمتغير الثابت على مستوى الملف:

  • يمكن أن تتداخل مساحات الأسماء المجهولة مع بعضها البعض، مما يوفر مستويات متعددة من الحماية لا يمكن للرموز الهروب منها.
  • يمكن وضع العديد من مساحات الأسماء المجهولة في نفس الملف المصدر، مما يؤدي إلى إنشاء نطاقات مختلفة على المستوى الثابت داخل نفس الملف.

سأكون مهتمًا بمعرفة ما إذا كان أي شخص قد استخدم مساحات أسماء مجهولة في كود حقيقي.

وهناك فرق مترجم محددة بين مساحات أسماء مجهولة وظائف ثابتة ويمكن رؤية ترجمة التعليمات البرمجية التالية.

#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;
}

وتجميع هذا الرمز مع VS 2017 (تحديد العلم تحذير مستوى 4 / W4 لتمكين <لأ href = "https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler -warning المستوى-4-c4505 "يختلط =" نوفولو noreferrer "> تحذير C4505: وظيفة المحلية غير مرجعية تم إزالتها) ودول مجلس التعاون الخليجي 4.9 مع وظيفة -Wunused أو علم الجدار شاحن يدل على أن VS 2017 سوف تنتج فقط تحذير لوظيفة ثابتة غير المستخدمة. دول مجلس التعاون الخليجي 4.9 وأعلى، وكذلك رنة 3.3 وأعلى، وسوف تنتج تحذيرات عن وظيفة غير مرجعية في مساحة الاسم وكذلك تحذير لوظيفة ثابتة غير المستخدمة.

تجريبي لايف من دول مجلس التعاون الخليجي 4.9 و MSVC 2017

أنا شخصياً أفضّل الوظائف الثابتة على مساحات الأسماء بدون اسم للأسباب التالية:

  • من الواضح والواضح من تعريف الوظيفة وحدها أنها خاصة بوحدة الترجمة حيث يتم تجميعها.باستخدام مساحة الاسم بدون اسم، قد تحتاج إلى التمرير والبحث لمعرفة ما إذا كانت الوظيفة موجودة في مساحة الاسم.

  • قد يتم التعامل مع الوظائف في مساحات الأسماء على أنها خارجية بواسطة بعض المترجمين (الأقدم).في VS2017 ما زالوا خارجيين.لهذا السبب، حتى لو كانت الوظيفة في مساحة اسم بدون اسم، فقد لا تزال ترغب في وضع علامة عليها ثابتة.

  • تتصرف الوظائف الثابتة بشكل مشابه جدًا في C أو C++، بينما من الواضح أن مساحات الأسماء غير المسماة هي C++ فقط.تضيف مساحات الأسماء بدون اسم أيضًا مستوى إضافيًا في حالة وجود مسافة بادئة وأنا لا أحب ذلك :)

لذا، يسعدني أن أرى هذا الاستخدام للوظائف الثابتة لم يتم إهمالها بعد الآن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top