c++ معنى - لماذا يعتبر استخدام "مساحة الاسم القياسية" ممارسة سيئة؟




شرح using (25)

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

لذا فقط اعتبرهم يعملوا كأسماء محجوزة مثل "int" أو "class" وهذا هو.

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

لقد قيل لي من قبل الآخرين أن الكتابة using namespace std في using namespace std في الكود غير صحيح ، وأنه يجب استخدام std::cout و std::cin بدلاً من ذلك.

لماذا يعتبر using namespace std ممارسة سيئة؟ هل هو غير فعال أم أنه يخاطر بالتعبير عن المتغيرات الملتبسة (المتغيرات التي تشترك في الاسم نفسه كدالة في مساحة الاسم ( std )؟ هل يؤثر على الأداء؟


هذا لا يرتبط بالأداء على الإطلاق. ولكن ضع في اعتبارك ذلك: أنت تستخدم مكتبتين تدعى Foo and Bar:

using namespace foo;
using namespace bar;

كل شيء يعمل بشكل جيد ، يمكنك استدعاء Blah() من Foo و Quux() من شريط دون مشاكل. ولكن في يوم من الأيام تقوم بالترقية إلى إصدار جديد من Foo 2.0 ، والذي يقدم الآن وظيفة تسمى Quux() . الآن لديك مشكلة: كل من Foo 2.0 و Bar import Quux() في مساحة الاسم العالمية الخاصة بك. هذا سوف يستغرق بعض الجهد لإصلاح ، لا سيما إذا كانت المعلمات الدالة تتطابق.

إذا كنت قد استخدمت foo::Blah() و bar::Quux() ، فستكون مقدمة foo::Quux() بدون حدث.


كل شيء عن إدارة التعقيد. إن استخدام مساحة الاسم سيسحب الأشياء التي لا تريدها ، وبالتالي ربما يصعب تصحيحها (أقول ربما). استخدام std :: في كل مكان أصعب في القراءة (المزيد من النص وكل ذلك).

خيول الدورات - إدارة تعقيدك بأفضل طريقة ممكنة وشعورك بالقدرة.


أنا أيضا نعتبرها ممارسة سيئة. لماذا ا؟ يوم واحد فقط اعتقدت أن وظيفة مساحة الاسم هي لتقسيم الأشياء ، لذا لا ينبغي لي أن أفسدها مع رمي كل شيء في كيس عالمي واحد. ومع ذلك ، إذا كنت غالبا ما أستخدم "cout" و "cin" ، فإنني أكتب: using std::cout; using std::cin; using std::cout; using std::cin; في ملف cpp (أبداً في ملف الرأس لأنه ينتشر مع #include ). أعتقد أن أي شخص عاقل سوف يطلق اسمًا على cout أو cin . ؛)


أنا أتفق مع الآخرين هنا ، لكني أود أن أتطرق إلى المخاوف المتعلقة بقابلية القراءة - يمكنك تجنب كل ذلك ببساطة عن طريق استخدام الرموز المطبوعة في أعلى ملفك أو وظيفتك أو إعلان الفصل.

وعادة ما أستخدمه في إعلان الفئة الخاصة بي حيث تميل الأساليب في الفصل إلى التعامل مع أنواع البيانات المشابهة (الأعضاء) و typedef فرصة لتعيين اسم ذي معنى في سياق الفصل الدراسي. هذا في الواقع يساعد على سهولة القراءة في تعريفات طرق الصف.

//header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

وفي التنفيذ:

//cpp
Lines File::ReadLines()
{
    Lines lines;
    //get them...
    return lines;
}

في مقابل:

//cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    //get them...
    return lines;
}

أو:

//cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    //get them...
    return lines;
}

يعتبر

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

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

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


"لماذا" باستخدام مساحة الاسم القياسية ؛ يعتبر ممارسة سيئة في C ++؟ "

أضعه في الاتجاه الآخر: لماذا تعتبر الكتابة 5 أحرف إضافية مرهقة من قبل البعض؟

فكر مثلاً في كتابة جزء من برنامج عددي ، فلماذا أفكر حتى في تلويث مساحيتي العالمية عن طريق قطع "std :: vector" بشكل عام إلى "vector" عندما يكون "vector" أحد أهم مفاهيم نطاق المشكلة؟


يجب ألا يستخدم المرء استخدام التوجيه على النطاق العالمي ، خاصة في الرؤوس. ومع ذلك ، هناك حالات يكون من المناسب فيها حتى في ملف الرأس:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; //no problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

هذا أفضل من مؤهل صريح ( std::sin ، std::cos ...) لأنه أقصر ولديه القدرة على العمل مع أنواع الفاصلة العائمة المعرفة من قبل المستخدم (عن طريق وسيطة Dependent Lookup).


أنا ركض مؤخرا إلى شكوى حول Visual Studio 2010 . اتضح أن كل الملفات المصدر كانت تحتوي على هذين السطرين:

using namespace std;
using namespace boost;

وهناك الكثير من ميزات Boost في معيار C ++ 0x ، و Visual Studio 2010 يحتوي على الكثير من ميزات C ++ 0x ، فجأة لم يتم تجميع هذه البرامج.

لذلك ، تجنب using namespace X; هو شكل من أشكال التدقيق المستقبلي ، وهي طريقة للتأكد من أن التغيير في المكتبات و / أو ملفات الرأس المستخدمة لا يؤدي إلى كسر أحد البرامج.


مثال على ذلك عند استخدام مساحة الاسم القياسي std يرمي خطأ complilation بسبب غموض العد ، وهو أيضاً دالة في مكتبة خوارزمية.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}

إصدار قصير: لا تستخدم العمومية باستخدام الإعلانات أو التوجيهات في ملفات الرأس. لا تتردد في استخدامها في ملفات التنفيذ. هنا ما يجب على Herb Sutter و Andrei Alexandrescu قوله عن هذه المسألة في C ++ Coding Standards (bold for emphasis is mine):

ملخص

إن استخدامات مساحة الاسم هي من أجل راحتك ، وليس لك لإلحاقها بالآخرين: لا تقم أبدًا بكتابة تصريح استخدام أو توجيه باستخدام أمر قبل التوجيه #include.

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

نقاش

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


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

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    / / ...
}
namespace Yourlib{
    class Stack{ /* ... */ };
    / / ...
}
void f(int max) {
    Mylib: :Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

يمكن أن يكون تكرار اسم مساحة الاسم بمثابة إلهاء لكل من القراء والكتاب. وبالتالي ، يمكن الإشارة إلى أن الأسماء من مساحة اسم معينة متوفرة بدون تأهيل صريح. فمثلا:

void f(int max) {
    using namespace Mylib; / / make names from Mylib accessible
    Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

توفر مساحات الأسماء أداة فعالة لإدارة المكتبات المختلفة وإصدارات مختلفة من الكود. على وجه الخصوص ، فإنها توفر بدائل مبرمج من كيفية صريحة لجعل إشارة إلى اسم غير محلي.

المصدر: نظرة عامة على لغة برمجة C ++ من قبل Bjarne Stroustrup


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

أعني حقاً ... أقول "لا تعتمد على هذا الوجود" هو مجرد إعدادك للاعتماد عليه غير موجود. ستواجه دائمًا مشكلات في استعارة مقتطفات الشفرة وإصلاحها باستمرار. فقط احتفظ بأشياء محددة من قبل المستخدم واقترحت في نطاق محدود كما ينبغي وينبغي أن تكون متحمسة للغاية مع globals (بصدق globals ينبغي أن يكون دائما الملاذ الأخير لأغراض "تجميع الآن ، التعقل في وقت لاحق"). حقا أعتقد أنها نصيحة سيئة من معلمك لأن استخدام std سيعمل لكل من "cout" و "std :: cout" ولكن NOT ستعمل باستخدام std ستعمل فقط لـ "std :: cout". لن تكون دائمًا محظوظًا بما يكفي لكتابة جميع الرموز الخاصة بك.

ملاحظة: لا تركز كثيرًا على مشكلات الكفاءة حتى تتعلم قليلاً عن كيفية عمل المجمعين. مع القليل من الترميز التجريبي ، لا يتعين عليك تعلم الكثير عنها قبل أن تدرك مدى قدرتها على تعميم كود جيد إلى شيء بسيط. كل البساطة كما لو كنت كتبت كل شيء في C. كود جيد هو فقط معقد كما يجب أن يكون.


المشكلة مع using namespace في ملفات رأس الفئات الخاصة بك هو أنه يفرض على أي شخص يريد استخدام الفئات الخاصة بك (بتضمين ملفات الرأس الخاصة بك) أن يكون أيضًا 'استخدام' (أي رؤية كل شيء في) مساحات الأسماء الأخرى.

ومع ذلك ، قد لا تتردد في وضع عبارة استخدام في ملفات (.) * .cpp الخاصة بك.

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

يوجد التوجيه الموجه الخاص بكود C ++ القديم ولتسهيل الانتقال إلى مساحات الأسماء ، ولكن ربما لا يجب استخدامه بشكل منتظم ، على الأقل ليس في رمز C ++ الجديد.

تقترح الأسئلة الشائعة بديلين:

  • إعلان استخدام:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • مجرد كتابة الأمراض المنقولة جنسيا ::

    std::cout << "Values:";
    

إذا قمت باستيراد ملفات رأس الصفحة الصحيحة ، فستحصل فجأة على أسماء مثل hex أو left أو plus أو count في count العالمي. قد يكون هذا مفاجئًا إذا لم تكن على علم بأن std:: يحتوي على هذه الأسماء. إذا كنت تحاول أيضًا استخدام هذه الأسماء محليًا ، فقد يؤدي ذلك إلى بعض الارتباك.

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


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


وأنا أتفق مع الآخرين - إنها تسأل عن صدامات الأسماء ، والغموض ، ومن ثم فالحقيقة أقل وضوحا. على الرغم من أنني أرى استخدام using، إلا أن تفضيلي الشخصي هو الحد من ذلك. وأود أيضا أن تنظر بقوة في ما أشار إليه البعض الآخر:

إذا كنت ترغب في العثور على اسم وظيفة قد يكون اسمًا شائعًا إلى حد ما ، ولكنك تريد فقط العثور عليه في stdمساحة الاسم (أو العكس - تريد تغيير كل المكالمات غير الموجودة في مساحة الاسم std، مساحة الاسم X، ...) ، ثم كيف تقترح للقيام بذلك؟ هل يمكنك كتابة برنامج للقيام بذلك ، ولكن أليس من الأفضل قضاء بعض الوقت في العمل على مشروعك بنفسك بدلاً من كتابة برنامج للحفاظ على مشروعك؟

شخصيا أنا لا أمانع std::البادئة. أنا أحب المظهر أكثر من عدم وجوده. لا أعرف ما إذا كان ذلك لأنه صريح ويقول لي "هذه ليست شيفتي ... أنا أستخدم المكتبة القياسية" أو إذا كانت شيئًا آخر ، لكنني أعتقد أنه يبدو أجمل. قد يكون هذا غريبا لأنني حصلت مؤخرا فقط على C ++ (استخدمت وما زالت C و لغات أخرى لفترة أطول و C هي لغتي المفضلة في كل العصور ، مباشرة فوق التجميع).

هناك شيء آخر على الرغم من أنه يرتبط إلى حد ما بما ذكر أعلاه وما يشير إليه الآخرون. في حين أن هذا قد يكون ممارسة سيئة ، فأنا أحتفظ في بعض الأحيان std::nameبنسخة المكتبة القياسية واسم التنفيذ الخاص بالبرنامج. نعم بالفعل هذا يمكن أن يعضك ويعضك بقوة ولكن كل ذلك يعود إلى أنني بدأت هذا المشروع من الصفر وأنا المبرمج الوحيد لذلك. مثال: I الزائد std::stringوالذي يطلق عليه string. لدي إضافات مفيدة. لقد فعلت ذلك جزئيا بسبب اتجاهي C و Unix (+ Linux) نحو الأسماء الصغيرة.

بالإضافة إلى ذلك ، يمكنك الحصول على أسماء مستعارة. هنا مثال على ما هو مفيد قد لا يكون قد تمت الإشارة إليه. أنا استخدم معيار C ++ 11 وبالتحديد مع libstdc ++. حسنا ، ليس لديها std::regexدعم كامل . من المؤكد أنه يجمع ولكن يطرح استثناء على طول الخطوط لكونه خطأ في نهاية المبرمج. لكن الافتقار إلى التنفيذ. إذن فإني كيف حللت ذلك. قم بتثبيت تعبير Boost ، اربطه. ثم ، أفعل ما يلي حتى عندما يكون libstdc ++ قد نفذ بالكامل ، أحتاج فقط إلى إزالة هذا الكود والشفرة تبقى كما هي:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;  
}

لن أجادل حول ما إذا كانت هذه فكرة سيئة أم لا. ومع ذلك سأجادل أنه يبقيها نظيفة لمشروعي وفي الوقت نفسه يجعلها محددة: صحيح لا بد لي من استخدام دفعة ولكن أنا استخدمه مثل libstdc ++ سيكون في نهاية المطاف. نعم ، بدء مشروعك الخاص والبدء بمعيار (...) في البداية يقطع شوطًا طويلاً جدًا مع المساعدة في الصيانة والتطوير وكل ما يتعلق بالمشروع!

تصحيح:
الآن لدي الوقت ، فقط لتوضيح شيء ما. لا أعتقد في الواقع أنها فكرة جيدة لاستخدام اسم لفصل دراسي / أي شيء في المحكمة الخاصة بلبنان بشكل مقصود وبشكل أكثر تحديدًا بدلاً من. السلسلة هي الاستثناء (تجاهل الأول ، أعلاه ، أو الثاني هنا ، punth إذا كان يجب عليك) بالنسبة لي كما لم يعجبني فكرة 'String'. كما هو ، لا أزال متحيزًا للغاية تجاه C ومنحازة ضد C ++. تفاصيل التفاصيل ، الكثير من ما أعمله على نوبات C أكثر (لكنه كان تمرينًا جيدًا وطريقة جيدة لإثبات نفسي. تعلم لغة أخرى و b. لا تحاول أن تكون أقل انحيازًا ضد الكائن / الفصول / وما إلى ذلك. كلما كان ذلك أقل انغماسًا ، وأقل تغطرسًا ، وأكثر قبولًا.). ولكن ما هو مفيد هو ما اقترحه البعض بالفعل: أنا بالفعل استخدم القائمة (إنها عامة نوعًا ما ، أليس كذلك؟) ،نوع (نفس الشيء) لاسم اثنين من شأنه أن يسبب اشتباك اسم لو كنت أفعلusing namespace std;ولهذا السبب ، أفضّل أن أكون محددًا ، وأتحكم في الأمر وأعرف أنه إذا كنت أعتزم استخدامه ، فسيتعين عليّ تحديده. بكل بساطة: لا يفترض السماح.

وأما بالنسبة لجعل Boost's regex جزءًا من std. أفعل ذلك من أجل التكامل المستقبلي - وأكرر مرة أخرى أنني أعترف بهذا التحيز بشكل كامل - لا أعتقد أنه قبيح بقدر boost::regex:: ...ما هو شيء آخر بالنسبة لي. هناك العديد من الأشياء في C ++ التي ما زال يجب أن أتقبلها بالكامل في النظرات والأساليب (مثال آخر: القوالب المتباينة مقابل var args [على الرغم من أنني أعترف بأن النماذج المتغيرة مفيدة جدًا!]). حتى أولئك الذين أقبلهم كان صعباً وما زلت أواجه مشكلات معهم.


من خبراتي ، إذا كانت لديك مكتبات متعددة تستخدمها cout، لكن لغرض مختلف ، فقد تستخدم الخطأ cout.

على سبيل المثال، إذا كنت اكتب في، using namespace std;و using namespace otherlib;واكتب فقط cout (الذي صادف أن يكون في كليهما)، بدلا من std::cout(أو 'otherlib::cout')، قد تستخدم خطأ واحد، والحصول على الأخطاء، هو أكثر فعالية بكثير وكفاءة استخدام std::cout.


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

و namespace stdيحتوي على وظائف والمتغيرات القياسية C ++. تعد مساحة الاسم هذه مفيدة عند استخدام وظائف C ++ القياسية في كثير من الأحيان.

كما هو مذكور في هذه page :

تعتبر العبارة باستخدام مساحة الاسم std بشكل عام من الممارسات السيئة. يتمثل البديل لهذا البيان في تحديد مساحة الاسم التي ينتمي إليها المعرف باستخدام عامل النطاق (: :) في كل مرة نعلن فيها نوعًا ما.

وانظر هذا الرأي :

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

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

كما هو مذكور في هذه page :

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

...

الآن في مرحلة لاحقة من التطوير ، نرغب في استخدام نسخة أخرى من cout يتم تنفيذها بشكل مخصص في بعض المكتبات تسمى "foo" (على سبيل المثال)

...

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


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

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


هذه ممارسة سيئة ، تعرف في الغالب باسم تلوث مساحة الاسم العالمي. قد تحدث المشاكل عندما يكون لدى مساحة اسم واحدة أكثر من نفس اسم الوظيفة مع التوقيع ، ثم سيكون من الغموض أن يقرر المترجم أي واحد يجب الاتصال به ويمكن تجنب كل هذا عند تحديد مساحة الاسم مع استدعاء الوظيفة الخاصة بك std::cout. أتمنى أن يساعدك هذا. :)


مثال ملموس لتوضيح القلق. تخيل أن لديك موقفًا يحتوي على مكتبتين ، foo و bar ، كل منهما بهما مساحة الاسم الخاصة بهما:

namespace foo {
    void a(float) { /* does something */ }
}

namespace bar {
    ...
}

الآن لنفترض أنك تستخدم foo وشريطًا معًا في برنامجك الخاص على النحو التالي:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

عند هذه النقطة كل شيء على ما يرام. عندما تقوم بتشغيل برنامجك "يفعل شيئا". ولكن في وقت لاحق تحديث شريط ودعنا نقول أنه قد تغير ليصبح مثل:

namespace bar {
    void a(float) { /* does something completely different */ }
}

عند هذه النقطة ستحصل على خطأ في برنامج التحويل البرمجي:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

لذلك ستحتاج إلى إجراء بعض الصيانة لتوضيح "أ" تعني (أي foo::a). هذا ربما غير مرغوب فيه ، ولكن لحسن الحظ أنه من السهل جدا (فقط إضافة foo::أمام جميع المكالمات إلى aأن علامات المجمع على أنها غامضة).

ولكن تخيل سيناريو بديل حيث تغير الشريط بدلاً من ذلك ليبدو هكذا:

namespace bar {
    void a(int) { /* does something completely different */ }
}

عند هذه النقطة دعوتكم ل a(42)يربط فجأة bar::aبدلا من foo::aوبدلا من القيام 'شيء' يفعل "شيئا مختلفا تماما. لا تحذير المترجم أو أي شيء. يبدأ برنامجك بصمت في عمل شيء مختلف تمامًا عن ذي قبل.

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

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


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


من الجيد رؤية الرمز ومعرفة ما يفعله. إذا رأيت std::cout أعلم أن دفق cout للمكتبة std . إذا رأيت cout فأنا لا أعرف. يمكن أن يكون دفق cout للمكتبة std . أو يمكن أن يكون هناك int cout = 0; عشرة خطوط أعلى في نفس الوظيفة. أو متغير static اسمه cout في هذا الملف. يمكن أن يكون أي شيء.

الآن ، احصل على مليون رمز سطر ، وهو ليس كبيرًا بشكل خاص ، وكنت تبحث عن خطأ ، مما يعني أنك تعرف أن هناك سطرًا واحدًا في هذه المليون سطر لا يفعل ما يفترض القيام به. cout << 1; يمكن قراءة static int المسماة cout ، وتحولها إلى اليسار من جانب واحد ، ورمي النتيجة. تبحث عن علة ، فما استقاموا لكم فاستقيموا للتحقق من ذلك. هل يمكنك أن ترى كيف أفضّل حقاً رؤية std::cout ؟

إنها واحدة من هذه الأشياء التي تبدو فكرة جيدة إذا كنت معلمًا ولم تضطر أبدًا إلى الكتابة والحفاظ على أي رمز لقمة العيش. أنا أحب رؤية رمز حيث (1) وأنا أعلم ما يفعل ؛ و (2) أنا واثق من أن الشخص الذي يكتبها يعرف ما يفعله.


أوصي بتجنب std::wstring على Windows أو في أي مكان آخر ، إلا عند الحاجة من قبل الواجهة ، أو في أي مكان بالقرب من مكالمات Windows API وتحويلات الترميز الخاصة بها كسكر نحوي.

تم تلخيص وجهة نظري في http://utf8everywhere.org والتي أنا مؤلف مشارك لها.

ما لم يكن التطبيق الخاص بك هو API-call-centric ، على سبيل المثال تطبيق واجهة المستخدم بشكل أساسي ، فإن الاقتراح هو تخزين سلاسل Unicode في سلسلة std :: وترميزها في UTF-8 ، إجراء التحويل بالقرب من مكالمات API. الفوائد الواردة في المقال تفوق الانزعاج الظاهري للتحويل ، خاصة في التطبيقات المعقدة. هذا هو مضاعف لذلك لتطوير منصة متعددة والمكتبة.

والآن ، الإجابة على أسئلتك:

  1. بعض الاسباب الضعيفة. وهي موجودة لأسباب تاريخية ، حيث يعتقد أن widechars هي الطريقة الصحيحة لدعم Unicode. يتم استخدامه الآن لواجهة APIs التي تفضل سلاسل UTF-16. أنا استخدمها فقط في المنطقة المجاورة لمكالمات API.
  2. هذا ليس له علاقة std :: string. يمكن أن تحمل أي ترميز وضعت فيه. والسؤال الوحيد هو كيف تعامل المحتوى الخاص بك. توصيلي هو UTF-8 ، لذا سيكون بإمكانه الاحتفاظ بجميع أحرف unicode بشكل صحيح. إنها ممارسة شائعة في لينكس ، لكنني أعتقد أن برامج Windows يجب أن تقوم بها أيضًا.
  3. لا.
  4. حرف واسع هو اسم مربك. في الأيام الأولى من Unicode ، كان هناك اعتقاد بأن الحرف يمكن ترميزه في وحدتي بايت ، ومن هنا جاءت التسمية. واليوم ، يقف "لأي جزء من الحرف الذي يبلغ طوله وحدتي بايت". يُنظر إلى UTF-16 كتسلسل لأزواج البايت هذه (ويعرف أيضًا باسم الأحرف الكبيرة). تأخذ الأحرف في UTF-16 إما زوجًا واحدًا أو اثنين.




c++ namespaces std using-directives c++-faq