เหตุใดจึง“ ใช้เนมสเปซ std;” ถือว่าปฏิบัติไม่ดี?

Sep 21 2009

ฉันได้รับแจ้งจากคนอื่นว่าการเขียนusing namespace std;โค้ดผิดและฉันควรใช้std::coutและใช้std::cinแทนโดยตรง

เหตุใดจึงusing namespace std;ถือเป็นการปฏิบัติที่ไม่ดี? ไม่มีประสิทธิภาพหรือเสี่ยงต่อการประกาศตัวแปรที่ไม่ชัดเจน (ตัวแปรที่ใช้ชื่อเดียวกันกับฟังก์ชันในstdเนมสเปซ) หรือไม่ มีผลต่อประสิทธิภาพหรือไม่?

คำตอบ

2351 GregHewgill Sep 21 2009 at 10:13

สิ่งนี้ไม่เกี่ยวข้องกับประสิทธิภาพ แต่อย่างใด แต่ลองพิจารณาสิ่งนี้: คุณกำลังใช้ไลบรารีสองแห่งที่เรียกว่า Foo and Bar:

using namespace foo;
using namespace bar;

ทุกอย่างทำงานได้ดีและคุณสามารถโทรBlah()จาก Foo และQuux()จาก Bar ได้โดยไม่มีปัญหา แต่วันหนึ่งคุณอัปเกรดเป็น Foo 2.0 เวอร์ชันใหม่ซึ่งตอนนี้มีฟังก์ชันที่เรียกว่าQuux(). ตอนนี้คุณมีข้อขัดแย้ง: ทั้ง Foo 2.0 และ Bar จะนำเข้าQuux()สู่เนมสเปซส่วนกลางของคุณ จะต้องใช้ความพยายามในการแก้ไขโดยเฉพาะอย่างยิ่งหากพารามิเตอร์ของฟังก์ชันตรงกัน

หากคุณเคยใช้foo::Blah()และbar::Quux()การแนะนำfoo::Quux()จะไม่ใช่เหตุการณ์

1442 sbi Sep 21 2009 at 16:26

ฉันเห็นด้วยกับทุกสิ่งที่เกร็กเขียนแต่ฉันอยากจะเพิ่ม: มันอาจแย่กว่าที่เกร็กพูดเสียอีก!

ไลบรารี Foo 2.0 สามารถแนะนำฟังก์ชันซึ่งQuux()ตรงกับการโทรบางส่วนของคุณได้Quux()ดีกว่าbar::Quux()รหัสของคุณที่เรียกมาหลายปีอย่างไม่น่าสงสัย จากนั้นโค้ดของคุณจะยังคงคอมไพล์แต่มันเรียกใช้ฟังก์ชันที่ไม่ถูกต้องอย่างเงียบ ๆและทำสิ่งที่พระเจ้ารู้ นั่นเป็นเรื่องที่เลวร้ายที่สุดเท่าที่สิ่งต่างๆจะได้รับ

เก็บไว้ในใจว่าstdnamespace มีตันของตัวระบุหลายแห่งซึ่งมีมากคนทั่วไป (คิดว่าlist, sort, string, iteratorฯลฯ ) ซึ่งมีโอกาสมากที่จะปรากฏในรหัสอื่น ๆ ด้วย

หากคุณคิดว่าสิ่งนี้ไม่น่าเป็นไปได้: มีคำถามที่ถามที่นี่ใน Stack Overflow ซึ่งสิ่งนี้เกิดขึ้นค่อนข้างมาก (เรียกฟังก์ชันผิดเนื่องจากstd::คำนำหน้าถูกละไว้) ประมาณครึ่งปีหลังจากที่ฉันให้คำตอบนี้ นี่คืออีกตัวอย่างล่าสุดของคำถามดังกล่าว นี่จึงเป็นปัญหาที่แท้จริง


นี่คือจุดข้อมูลเพิ่มเติมที่หนึ่ง: std::หลายหลายปีที่ผ่านมาผมยังใช้เพื่อพบว่ามันน่ารำคาญต้องทุกอย่างคำนำหน้าจากห้องสมุดมาตรฐานที่มี จากนั้นฉันก็ทำงานในโครงการที่มีการตัดสินใจตั้งแต่เริ่มต้นว่าทั้งusingคำสั่งและการประกาศถูกห้ามยกเว้นขอบเขตของฟังก์ชัน เดาอะไร? พวกเราส่วนใหญ่ใช้เวลาไม่กี่สัปดาห์ในการเขียนคำนำหน้าและหลังจากนั้นไม่กี่สัปดาห์พวกเราส่วนใหญ่ก็เห็นพ้องกันว่ารหัสนี้ทำให้อ่านได้ง่ายขึ้น มีเหตุผลสำหรับสิ่งนั้น: ไม่ว่าคุณจะชอบร้อยแก้วที่สั้นกว่าหรือยาวกว่านั้นเป็นเรื่องส่วนตัว แต่คำนำหน้าจะเพิ่มความชัดเจนให้กับโค้ด ไม่เพียง แต่คอมไพเลอร์เท่านั้น แต่คุณยังพบว่าตัวระบุใดถูกอ้างถึงได้ง่ายขึ้นด้วย

ในทศวรรษที่ผ่านมาโครงการดังกล่าวมีโค้ดหลายล้านบรรทัด เนื่องจากการอภิปรายเหล่านี้เกิดขึ้นครั้งแล้วครั้งเล่าฉันเคยสงสัยว่าขอบเขตฟังก์ชัน (อนุญาต) usingถูกใช้ในโครงการบ่อยเพียงใด ฉันโลภแหล่งที่มาของมันและพบเพียงหนึ่งหรือสองแห่งเท่านั้นที่มันถูกใช้ สำหรับฉันสิ่งนี้บ่งชี้ว่าเมื่อลองแล้วนักพัฒนาไม่รู้สึกstd::เจ็บปวดพอที่จะใช้คำสั่งแม้แต่ครั้งเดียวในทุกๆ 100 kLoC แม้ว่าจะได้รับอนุญาตให้ใช้ก็ตาม


บรรทัดล่าง: คำนำหน้าทุกอย่างอย่างชัดเจนไม่ก่อให้เกิดอันตรายใด ๆ ใช้เวลาทำความคุ้นเคยน้อยมากและมีข้อดีตามวัตถุประสงค์ โดยเฉพาะอย่างยิ่งมันทำให้โค้ดตีความได้ง่ายขึ้นโดยคอมไพเลอร์และโดยผู้อ่านที่เป็นมนุษย์และนั่นน่าจะเป็นเป้าหมายหลักเมื่อเขียนโค้ด

453 ChrisW Sep 21 2009 at 10:22

ปัญหาusing namespaceในการใส่ไฟล์ส่วนหัวของชั้นเรียนของคุณคือการบังคับให้ทุกคนที่ต้องการใช้ชั้นเรียนของคุณ (โดยรวมไฟล์ส่วนหัวของคุณ) ต้อง 'ใช้' (เช่นเห็นทุกอย่างใน) เนมสเปซอื่น ๆ เหล่านั้น

อย่างไรก็ตามคุณสามารถใส่คำสั่งการใช้งานลงในไฟล์ (ส่วนตัว) * .cpp ของคุณได้


ระวังว่าบางคนไม่เห็นด้วยกับคำพูดของฉันว่า "รู้สึกอิสระ" แบบนี้ - เพราะแม้ว่าusingคำสั่งในไฟล์ cpp จะดีกว่าในส่วนหัว (เนื่องจากไม่มีผลกับคนที่รวมไฟล์ส่วนหัวของคุณ) แต่พวกเขาคิดว่ามันยังไม่ใช่ดี (เพราะขึ้นอยู่กับรหัสมันอาจทำให้การใช้งานคลาสยากขึ้นในการบำรุงรักษา) รายการคำถามที่พบบ่อยของ C ++ Super นี้กล่าวว่า

คำสั่งการใช้มีอยู่สำหรับรหัส C ++ เดิมและเพื่อให้การเปลี่ยนไปใช้เนมสเปซง่ายขึ้น แต่คุณอาจไม่ควรใช้เป็นประจำอย่างน้อยก็ไม่ใช่ในรหัส C ++ ใหม่ของคุณ

คำถามที่พบบ่อยเสนอทางเลือกสองทาง:

  • การใช้คำประกาศ:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • เพียงพิมพ์ std ::

    std::cout << "Values:";
    
241 DavidThornley Oct 29 2010 at 00:37

ฉันเพิ่งวิ่งเข้าไปร้องเรียนเกี่ยวกับVisual Studio 2010 ปรากฎว่าไฟล์ต้นฉบับทั้งหมดมีสองบรรทัดนี้:

using namespace std;
using namespace boost;

ฟีเจอร์Boostจำนวนมากเข้าสู่มาตรฐาน C ++ 0x และ Visual Studio 2010 มีคุณสมบัติ C ++ 0x จำนวนมากดังนั้นโปรแกรมเหล่านี้จึงไม่ได้รวบรวม

ดังนั้นการหลีกเลี่ยงusing namespace X;จึงเป็นรูปแบบหนึ่งของการพิสูจน์ในอนาคตวิธีหนึ่งในการตรวจสอบให้แน่ใจว่าการเปลี่ยนแปลงไลบรารีและ / หรือไฟล์ส่วนหัวที่ใช้อยู่จะไม่ทำให้โปรแกรมเสียหาย

216 mattnewport Nov 04 2014 at 03:00

เวอร์ชันสั้น: อย่าใช้usingการประกาศหรือคำสั่งส่วนกลางในไฟล์ส่วนหัว อย่าลังเลที่จะใช้ในไฟล์การนำไปใช้งาน นี่คือสิ่งที่Herb SutterและAndrei Alexandrescuกล่าวเกี่ยวกับปัญหานี้ในมาตรฐานการเข้ารหัส C ++ (ตัวหนาเพื่อเน้นเป็นของฉัน):

สรุป

การใช้เนมสเปซเป็นไปเพื่อความสะดวกของคุณไม่ใช่เพื่อให้คุณสร้างความเสียหายแก่ผู้อื่นห้ามเขียนคำประกาศการใช้หรือคำสั่งการใช้ก่อนคำสั่ง #include

Corollary: ในไฟล์ส่วนหัวอย่าเขียนระดับเนมสเปซโดยใช้คำสั่งหรือใช้การประกาศ แทนเนมสเปซอย่างชัดเจน - รับรองชื่อทั้งหมด (กฎข้อที่สองตามมาจากข้อแรกเนื่องจากส่วนหัวไม่สามารถรู้ได้ว่า #includes ส่วนหัวอื่นอาจปรากฏตามหลังอะไร)

อภิปรายผล

กล่าวโดยย่อ: คุณสามารถและควรใช้เนมสเปซโดยใช้การประกาศและคำสั่งอย่างเสรีในไฟล์การนำไปใช้งานของคุณหลังจาก #include directives และรู้สึกดีกับมัน แม้จะมีการยืนยันซ้ำ ๆ ในทางตรงกันข้าม แต่เนมสเปซที่ใช้การประกาศและคำสั่งก็ไม่ใช่สิ่งชั่วร้ายและไม่ได้เอาชนะจุดประสงค์ของเนมสเปซ แต่เป็นสิ่งที่ทำให้เนมสเปซใช้งานได้

128 robson3.14 Sep 21 2009 at 22:47

เราไม่ควรใช้usingคำสั่งในขอบเขตส่วนกลางโดยเฉพาะในส่วนหัว อย่างไรก็ตามมีบางสถานการณ์ที่เหมาะสมแม้ในไฟล์ส่วนหัว:

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... ) เนื่องจากสั้นกว่าและมีความสามารถในการทำงานกับประเภทจุดลอยตัวที่ผู้ใช้กำหนด (ผ่านการค้นหาตามอาร์กิวเมนต์ (ADL))

100 towi Jan 18 2013 at 16:34

ห้ามใช้ทั่วโลก

ก็ถือว่า "เลว" เท่านั้นเมื่อใช้ทั่วโลก เพราะ:

  • คุณเกะกะเนมสเปซที่คุณกำลังเขียนโปรแกรม
  • ผู้อ่านจะมีปัญหาในการดูว่าตัวระบุใดมาจากไหนเมื่อคุณใช้หลายusing namespace xyzตัว
  • สิ่งที่เป็นจริงสำหรับผู้อ่านซอร์สโค้ดของคุณคนอื่น ๆก็ยิ่งเป็นความจริงสำหรับผู้อ่านบ่อยที่สุดนั่นคือตัวคุณเอง กลับมาในปีหรือสองปีแล้วดู ...
  • หากคุณพูดถึงusing namespace stdคุณอาจไม่ทราบถึงสิ่งที่คุณคว้ามาทั้งหมดและเมื่อคุณเพิ่มรายการอื่น#includeหรือย้ายไปยังการแก้ไข C ++ ใหม่คุณอาจได้รับความขัดแย้งของชื่อที่คุณไม่ทราบ

คุณสามารถใช้ในประเทศ

ไปข้างหน้าและใช้มันในพื้นที่ (เกือบ) ได้อย่างอิสระ แน่นอนว่านี่เป็นการป้องกันไม่ให้คุณทำซ้ำstd::- และการทำซ้ำก็ไม่ดีเช่นกัน

สำนวนสำหรับใช้ในท้องถิ่น

ใน C ++ 03 มี idiom - รหัสสำเร็จรูป - สำหรับการใช้งานswapฟังก์ชันสำหรับคลาสของคุณ ขอแนะนำให้คุณใช้งานในพื้นที่จริงusing namespace std- หรืออย่างน้อยที่สุดusing std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

สิ่งนี้ใช้เวทมนตร์ต่อไปนี้:

  • คอมไพเลอร์จะเลือกstd::swapfor value_คือvoid std::swap(int, int).
  • หากคุณมีการvoid swap(Child&, Child&)ใช้งานเกินพิกัดคอมไพเลอร์จะเลือก
  • หากคุณไม่มีโอเวอร์โหลดคอมไพเลอร์จะใช้void std::swap(Child&,Child&)และพยายามสลับสิ่งเหล่านี้ให้ดีที่สุด

ด้วย C ++ 11 ไม่มีเหตุผลที่จะใช้รูปแบบนี้อีกต่อไป มีการstd::swapเปลี่ยนแปลงการนำไปใช้เพื่อค้นหาการโอเวอร์โหลดที่อาจเกิดขึ้นและเลือกมัน

81 sth Sep 21 2009 at 10:23

ถ้าคุณนำเข้าไฟล์ส่วนหัวด้านขวาคุณก็มีชื่อเช่นhex, left, plusหรือcountอยู่ในขอบเขตทั่วโลกของคุณ อาจเป็นเรื่องน่าแปลกใจหากคุณไม่ทราบว่าstd::มีชื่อเหล่านี้อยู่ หากคุณพยายามใช้ชื่อเหล่านี้ในเครื่องอาจทำให้เกิดความสับสนได้

หากข้อมูลมาตรฐานทั้งหมดอยู่ในเนมสเปซของตัวเองคุณก็ไม่ต้องกังวลว่าชื่อจะชนกับโค้ดหรือไลบรารีอื่น ๆ

52 MartinBeckett Sep 21 2009 at 10:13

อีกเหตุผลหนึ่งคือความประหลาดใจ

ถ้าฉันเห็นcout << blahแทนที่จะstd::cout << blahคิดว่านี่คืออะไรcout? เป็นเรื่องปกติcoutหรือไม่? มันเป็นอะไรที่พิเศษ?

49 AlexanderPoluektov Mar 29 2011 at 15:10

โปรแกรมเมอร์ที่มีประสบการณ์ใช้ทุกอย่างเพื่อแก้ปัญหาของพวกเขาและหลีกเลี่ยงสิ่งที่สร้างปัญหาใหม่และพวกเขาหลีกเลี่ยงการใช้คำสั่งระดับไฟล์ส่วนหัวด้วยเหตุผลที่แน่นอนนี้

โปรแกรมเมอร์ที่มีประสบการณ์พยายามหลีกเลี่ยงการระบุชื่อที่มีคุณสมบัติครบถ้วนในไฟล์ต้นฉบับของตน เหตุผลเล็ก ๆ น้อย ๆ สำหรับเรื่องนี้ก็คือว่ามันไม่สง่างามในการเขียนโค้ดมากขึ้นเมื่อโค้ดน้อยก็เพียงพอเว้นแต่มีเหตุผลที่ดี สาเหตุหลักคือการปิดการค้นหาขึ้นอยู่กับอาร์กิวเมนต์ (ADL)

เหตุผลดีๆเหล่านี้คืออะไร? บางครั้งโปรแกรมเมอร์ต้องการปิด ADL อย่างชัดเจนในบางครั้งพวกเขาต้องการทำให้ไม่ชัดเจน

ดังนั้นสิ่งต่อไปนี้ใช้ได้:

  1. การใช้คำสั่งระดับฟังก์ชันและการใช้การประกาศภายในการนำไปใช้งานของฟังก์ชัน
  2. ซอร์สไฟล์ระดับโดยใช้การประกาศภายในซอร์สไฟล์
  3. (บางครั้ง) ระดับไฟล์ต้นฉบับโดยใช้คำสั่ง
46 Oleksiy Aug 29 2013 at 16:44

ฉันยอมรับว่าไม่ควรใช้ทั่วโลก แต่ก็ไม่ได้ชั่วร้ายที่จะใช้ในท้องถิ่นเช่นในไฟล์namespace. นี่คือตัวอย่างจาก"ภาษาโปรแกรม C ++" :

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

ในตัวอย่างนี้เราได้แก้ไขความขัดแย้งของชื่อที่อาจเกิดขึ้นและความคลุมเครือที่เกิดจากการเรียบเรียง

ชื่อที่ประกาศอย่างชัดเจนที่นั่น (รวมถึงชื่อที่ประกาศโดยใช้การประกาศเช่นHis_lib::String) มีลำดับความสำคัญเหนือชื่อที่ทำให้เข้าถึงได้ในขอบเขตอื่นโดยใช้คำสั่ง ( using namespace Her_lib)

32 Yelonek Sep 21 2009 at 16:34

ฉันยังถือว่าเป็นการปฏิบัติที่ไม่ดี ทำไม? วันหนึ่งฉันคิดว่าหน้าที่ของเนมสเปซคือการแบ่งสิ่งของดังนั้นฉันจึงไม่ควรทำลายมันด้วยการโยนทุกอย่างลงในกระเป๋าใบเดียว

อย่างไรก็ตามถ้าฉันใช้ 'cout' และ 'cin' บ่อยๆฉันจะเขียน: using std::cout; using std::cin;ในไฟล์. cpp (ไม่เคยอยู่ในไฟล์ส่วนหัวเนื่องจากมันแพร่กระจายไปด้วย#include) ผมคิดว่าไม่มีใครเลยที่จะมีสติตั้งชื่อสตรีมหรือcout cin;)

27 gnasher729 Mar 14 2014 at 00:22

ยินดีที่ได้เห็นโค้ดและรู้ว่ามันทำอะไร ถ้าฉันเห็นstd::coutฉันรู้ว่านั่นคือcoutกระแสของstdห้องสมุด ถ้าเห็นcoutแล้วจะไม่รู้ มันอาจจะเป็นcoutกระแสของstdห้องสมุด หรืออาจมีint cout = 0;สิบบรรทัดสูงกว่าในฟังก์ชันเดียวกัน หรือstaticตัวแปรที่มีชื่อcoutอยู่ในไฟล์นั้น. มันอาจเป็นอะไรก็ได้

ตอนนี้ใช้ฐานรหัสล้านบรรทัดซึ่งไม่ใหญ่เป็นพิเศษและคุณกำลังค้นหาจุดบกพร่องซึ่งหมายความว่าคุณรู้ว่ามีหนึ่งบรรทัดในหนึ่งล้านบรรทัดนี้ที่ไม่ได้ทำตามที่ควรจะทำ cout << 1;สามารถอ่านstatic intชื่อcoutเลื่อนไปทางซ้ายทีละนิดแล้วทิ้งผลลัพธ์ กำลังมองหาจุดบกพร่องฉันต้องตรวจสอบสิ่งนั้น คุณเห็นไหมว่าฉันชอบดูมากstd::coutแค่ไหน?

เป็นหนึ่งในสิ่งเหล่านี้ที่ดูเหมือนเป็นความคิดที่ดีมากหากคุณเป็นครูและไม่ต้องเขียนและรักษารหัสใด ๆ เพื่อหาเลี้ยงชีพ ฉันชอบดูรหัสที่ (1) ฉันรู้ว่ามันทำอะไร และ (2) ฉันมั่นใจว่าคนที่เขียนมันรู้ว่ามันทำอะไร

25 PreetSangha Sep 21 2009 at 10:14

ทุกอย่างเกี่ยวกับการจัดการความซับซ้อน การใช้เนมสเปซจะดึงสิ่งต่างๆเข้ามาในสิ่งที่คุณไม่ต้องการและอาจทำให้การดีบักทำได้ยากขึ้น (ฉันบอกว่าอาจเป็นไปได้) การใช้ std :: ทั่วทุกที่นั้นอ่านยากกว่า (ข้อความเพิ่มเติมและทั้งหมดนั้น)

ม้าสำหรับหลักสูตร - จัดการความซับซ้อนของคุณว่าคุณทำได้ดีที่สุดและรู้สึกได้อย่างไร

20 RonWarholic Sep 21 2009 at 10:19

พิจารณา

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


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

class stringstream {  // Uh oh
};

โปรดทราบว่านี่เป็นตัวอย่างง่ายๆ หากคุณมีไฟล์ที่มีการรวม 20 ไฟล์และการนำเข้าอื่น ๆ คุณจะมีการอ้างอิงมากมายที่จะต้องดำเนินการเพื่อแก้ไขปัญหา สิ่งที่แย่กว่านั้นคือคุณอาจได้รับข้อผิดพลาดที่ไม่เกี่ยวข้องในโมดูลอื่น ๆ ขึ้นอยู่กับคำจำกัดความที่ขัดแย้งกัน

มันไม่ได้น่ากลัว แต่คุณจะไม่ต้องปวดหัวด้วยการไม่ใช้มันในไฟล์ส่วนหัวหรือเนมสเปซส่วนกลาง อาจเป็นเรื่องที่ถูกต้องที่จะทำในขอบเขตที่ จำกัด มาก แต่ฉันไม่เคยมีปัญหาในการพิมพ์อักขระห้าตัวพิเศษเพื่อชี้แจงว่าฟังก์ชันของฉันมาจากไหน

19 Kevin Sep 03 2016 at 03:06

ตัวอย่างที่เป็นรูปธรรมเพื่อชี้แจงข้อกังวล ลองนึกภาพคุณมีสถานการณ์ที่คุณมีสองไลบรารีfooและbarแต่ละแห่งมีเนมสเปซของตัวเอง:

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

namespace bar {
    ...
}

สมมติว่าคุณใช้fooและbarร่วมกันในโปรแกรมของคุณเองดังนี้:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

ณ จุดนี้ทุกอย่างเรียบร้อยดี เมื่อคุณเรียกใช้โปรแกรมของคุณมัน 'ทำอะไรบางอย่าง' แต่ต่อมาคุณอัปเดตbarและสมมติว่าเปลี่ยนเป็นดังนี้:

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)
}

ดังนั้นคุณจะต้องทำการบำรุงรักษาบางอย่างที่จะชี้แจงว่า 'a' foo::aหมาย นั่นเป็นสิ่งที่ไม่พึงปรารถนา แต่โชคดีที่มันค่อนข้างง่าย (เพียงเพิ่มfoo::หน้าการเรียกทั้งหมดเพื่อให้aคอมไพเลอร์ทำเครื่องหมายว่าคลุมเครือ)

แต่ลองนึกภาพสถานการณ์อื่นที่แถบเปลี่ยนไปเป็นแบบนี้แทน:

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

เมื่อมาถึงจุดนี้การเรียกของคุณจะa(42)ผูกเข้ากับbar::aแทนที่จะทำfoo::aและแทนที่จะทำ 'บางอย่าง' มันกลับ 'สิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง' ไม่มีคำเตือนคอมไพเลอร์หรืออะไรเลย โปรแกรมของคุณเพิ่งเริ่มทำสิ่งที่แตกต่างไปจากเดิมอย่างเงียบ ๆ

เมื่อคุณใช้เนมสเปซคุณกำลังเสี่ยงกับสถานการณ์เช่นนี้ซึ่งเป็นสาเหตุที่ทำให้ผู้คนไม่สบายใจที่จะใช้เนมสเปซ ยิ่งมีสิ่งต่างๆในเนมสเปซมากเท่าไหร่ความเสี่ยงของความขัดแย้งก็จะมากขึ้นดังนั้นผู้คนอาจไม่สบายใจในการใช้เนมสเปซstd(เนื่องจากจำนวนสิ่งต่างๆในเนมสเปซนั้น) มากกว่าเนมสเปซอื่น ๆ

ท้ายที่สุดแล้วนี่เป็นการแลกเปลี่ยนระหว่างความสามารถในการเขียนเทียบกับความน่าเชื่อถือ / ความสามารถในการบำรุงรักษา ความสามารถในการอ่านอาจเป็นปัจจัยด้วย แต่ฉันเห็นข้อโต้แย้งว่าไปทางใดทางหนึ่ง โดยปกติฉันจะบอกว่าความน่าเชื่อถือและความสามารถในการบำรุงรักษามีความสำคัญมากกว่า แต่ในกรณีนี้คุณจะต้องจ่ายค่าใช้จ่ายที่สามารถเขียนได้อย่างต่อเนื่องสำหรับผลกระทบด้านความน่าเชื่อถือ / การบำรุงรักษาที่ค่อนข้างหายาก การแลกเปลี่ยนที่ 'ดีที่สุด' จะเป็นตัวกำหนดโครงการและลำดับความสำคัญของคุณ

18 user2645752 Nov 09 2013 at 22:09

การใช้เนมสเปซจำนวนมากในเวลาเดียวกันนั้นเป็นสูตรสำหรับหายนะ แต่การใช้เพียงเนมสเปซstdและเนมสเปซเท่านั้นstdไม่ใช่เรื่องใหญ่ในความคิดของฉันเพราะการกำหนดนิยามใหม่สามารถเกิดขึ้นได้ด้วยรหัสของคุณเองเท่านั้น ...

ดังนั้นให้พิจารณาว่าฟังก์ชันเหล่านี้เป็นชื่อที่สงวนไว้เช่น "int" หรือ "class" เท่านี้เอง

คนเราควรเลิกยุ่งเกี่ยวกับเรื่องนี้ ครูของคุณพูดถูกตลอด เพียงใช้เนมสเปซเดียว นั่นคือจุดรวมของการใช้เนมสเปซตั้งแต่แรก คุณไม่ควรใช้มากกว่าหนึ่งในเวลาเดียวกัน เว้นแต่จะเป็นของคุณเอง. ดังนั้นอีกครั้งการกำหนดนิยามใหม่จะไม่เกิดขึ้น

18 DustinGetz Sep 21 2009 at 11:04
  1. คุณต้องสามารถอ่านโค้ดที่เขียนโดยผู้ที่มีสไตล์และแนวปฏิบัติที่ดีแตกต่างจากคุณ

  2. หากคุณใช้เพียงอย่างเดียวcoutไม่มีใครสับสน แต่เมื่อคุณมีเนมสเปซจำนวนมากบินไปมาและคุณเห็นคลาสนี้และคุณไม่แน่ใจว่ามันทำอะไรการมีเนมสเปซที่ชัดเจนจะทำหน้าที่เป็นความคิดเห็นประเภทต่างๆ คุณจะเห็นได้ในแวบแรกว่า "โอ้นี่เป็นการทำงานของระบบไฟล์" หรือ "กำลังทำเครือข่ายอยู่"

14 Carl Feb 12 2015 at 07:40

ฉันเห็นด้วยกับคนอื่น ๆ ที่นี่ แต่ฉันต้องการจัดการกับข้อกังวลเกี่ยวกับความสามารถในการอ่าน - คุณสามารถหลีกเลี่ยงสิ่งเหล่านี้ได้โดยใช้ typedef ที่ด้านบนของไฟล์ฟังก์ชันหรือการประกาศคลาสของคุณ

ฉันมักจะใช้ในการประกาศคลาสเนื่องจากวิธีการในชั้นเรียนมีแนวโน้มที่จะจัดการกับประเภทข้อมูลที่คล้ายกัน (สมาชิก) และ 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;
}
14 RohanSingh Apr 05 2015 at 19:56

เนมสเปซคือขอบเขตที่มีชื่อ เนมสเปซใช้เพื่อจัดกลุ่มการประกาศที่เกี่ยวข้องและเพื่อแยกรายการแยกต่างหาก ตัวอย่างเช่นไลบรารีที่พัฒนาแยกกันสองไลบรารีอาจใช้ชื่อเดียวกันเพื่ออ้างถึงรายการที่แตกต่างกัน แต่ผู้ใช้ยังคงสามารถใช้ทั้งสองอย่างได้:

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

11 Nithin Dec 31 2014 at 15:00

ตัวอย่างที่using namespace stdแสดงข้อผิดพลาดในการคอมไพล์เนื่องจากความไม่ชัดเจนของการนับซึ่งเป็นฟังก์ชันในไลบรารีอัลกอริทึมด้วย

#include <iostream>
#include <algorithm>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}
10 CryogenicNeo Apr 24 2018 at 00:15

ไม่ทำให้ประสิทธิภาพของซอฟต์แวร์หรือโครงการของคุณแย่ลง การรวมเนมสเปซที่จุดเริ่มต้นของซอร์สโค้ดของคุณนั้นไม่เลว การรวมusing namespace stdคำสั่งจะแตกต่างกันไปตามความต้องการของคุณและวิธีที่คุณกำลังพัฒนาซอฟต์แวร์หรือโครงการ

namespace stdมีฟังก์ชั่นมาตรฐาน C ++ และตัวแปร เนมสเปซนี้มีประโยชน์เมื่อคุณมักจะใช้ฟังก์ชันมาตรฐาน C ++

ดังที่กล่าวไว้ในหน้านี้:

คำสั่งโดยใช้ namespace std โดยทั่วไปถือว่าเป็นการปฏิบัติที่ไม่ดี อีกทางเลือกหนึ่งของคำสั่งนี้คือการระบุเนมสเปซที่ตัวระบุอยู่โดยใช้ตัวดำเนินการขอบเขต (: :) ทุกครั้งที่เราประกาศประเภท

และดูความคิดเห็นนี้ :

ไม่มีปัญหาในการใช้ "การใช้เนมสเปซ std" ในไฟล์ต้นฉบับของคุณเมื่อคุณใช้เนมสเปซอย่างหนักและรู้ว่าจะไม่มีอะไรชนกัน

บางคนบอกว่าเป็นแนวทางปฏิบัติที่ไม่ดีในการรวมusing namespace stdไฟล์ต้นฉบับไว้ในไฟล์ต้นฉบับของคุณเนื่องจากคุณกำลังเรียกใช้ฟังก์ชันและตัวแปรทั้งหมดจากเนมสเปซนั้น เมื่อคุณต้องการกำหนดฟังก์ชันใหม่ที่มีชื่อเดียวกันกับฟังก์ชันอื่นที่มีอยู่ในฟังก์ชันnamespace stdคุณจะโอเวอร์โหลดฟังก์ชันและอาจทำให้เกิดปัญหาเนื่องจากการคอมไพล์หรือดำเนินการ จะไม่รวบรวมหรือดำเนินการตามที่คุณคาดหวัง

ดังที่กล่าวไว้ในหน้านี้:

แม้ว่าคำสั่งจะช่วยให้เราไม่ต้องพิมพ์ std :: เมื่อใดก็ตามที่เราต้องการเข้าถึงคลาสหรือประเภทที่กำหนดไว้ในเนมสเปซ std แต่จะนำเข้าเนมสเปซ std ทั้งหมดลงในเนมสเปซปัจจุบันของโปรแกรม ให้เราใช้ตัวอย่างบางส่วนเพื่อทำความเข้าใจว่าเหตุใดสิ่งนี้จึงไม่ใช่สิ่งที่ดี

...

ในขั้นตอนต่อไปของการพัฒนาเราต้องการใช้ cout เวอร์ชันอื่นที่ปรับใช้เองในไลบรารีบางแห่งที่เรียกว่า "foo" (เช่น)

...

สังเกตว่ามีความคลุมเครืออย่างไร cout ชี้ไปที่ห้องสมุดใด คอมไพเลอร์อาจตรวจพบสิ่งนี้และไม่ได้คอมไพล์โปรแกรม ในกรณีที่เลวร้ายที่สุดโปรแกรมอาจยังคงคอมไพล์อยู่ แต่เรียกใช้ฟังก์ชันที่ไม่ถูกต้องเนื่องจากเราไม่เคยระบุว่าเป็นตัวระบุเนมสเปซใด

8 Dr.Watson Sep 21 2009 at 10:34

ฉันไม่คิดว่าจะเป็นการปฏิบัติที่ไม่ดีในทุกสภาวะ แต่คุณต้องระมัดระวังเมื่อใช้งาน หากคุณกำลังเขียนไลบรารีคุณควรใช้ตัวดำเนินการแก้ไขขอบเขตกับเนมสเปซเพื่อป้องกันไม่ให้ไลบรารีของคุณไปยุ่งกับไลบรารีอื่น ๆ สำหรับรหัสระดับแอปพลิเคชันฉันไม่เห็นว่ามีอะไรผิดปกติ

8 Noname Oct 14 2014 at 00:30

ฉันเห็นด้วยกับคนอื่น - มันคือการขอชื่อการปะทะกันความคลุมเครือและความจริงก็คือความชัดเจนน้อยลง แม้ว่าฉันจะเห็นการใช้งานusingแต่ความชอบส่วนตัวของฉันคือการ จำกัด มัน ฉันขอพิจารณาอย่างยิ่งว่าสิ่งที่คนอื่น ๆ ชี้ให้เห็น:

หากคุณต้องการค้นหาชื่อฟังก์ชันที่อาจเป็นชื่อธรรมดา แต่คุณต้องการค้นหาในstdเนมสเปซเท่านั้น (หรือย้อนกลับ - คุณต้องการเปลี่ยนการเรียกทั้งหมดที่ไม่ได้อยู่ในเนstdมสเปซเนมสเปซX... ) แล้วคุณเสนอให้ทำอย่างไร?

คุณสามารถเขียนโปรแกรมเพื่อทำมันได้ แต่จะดีกว่าไหมหากใช้เวลาในการทำโปรเจ็กต์ของคุณเองแทนที่จะเขียนโปรแกรมเพื่อดูแลโปรเจ็กต์ของคุณ

Personally, I actually don't mind the std:: prefix. I like the look more than not having it. I don't know if that is because it is explicit and says to me "this isn't my code... I am using the standard library" or if it is something else, but I think it looks nicer. This might be odd given that I only recently got into C++ (used and still do C and other languages for much longer and C is my favourite language of all time, right above assembly).

There is one other thing although it is somewhat related to the above and what others point out. While this might be bad practise, I sometimes reserve std::name for the standard library version and name for program-specific implementation. Yes, indeed this could bite you and bite you hard, but it all comes down to that I started this project from scratch, and I'm the only programmer for it. Example: I overload std::string and call it string. I have helpful additions. I did it in part because of my C and Unix (+ Linux) tendency towards lower-case names.

Besides that, you can have namespace aliases. Here is an example of where it is useful that might not have been referred to. I use the C++11 standard and specifically with libstdc++. Well, it doesn't have complete std::regex support. Sure, it compiles, but it throws an exception along the lines of it being an error on the programmer's end. But it is lack of implementation.

So here's how I solved it. Install Boost's regex, and link it in. Then, I do the following so that when libstdc++ has it implemented entirely, I need only remove this block and the code remains the same:

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

I won't argue on whether that is a bad idea or not. I will however argue that it keeps it clean for my project and at the same time makes it specific: True, I have to use Boost, but I'm using it like the libstdc++ will eventually have it. Yes, starting your own project and starting with a standard (...) at the very beginning goes a very long way with helping maintenance, development and everything involved with the project!

Just to clarify something: I don't actually think it is a good idea to use a name of a class/whatever in the STL deliberately and more specifically in place of. The string is the exception (ignore the first, above, or second here, pun if you must) for me as I didn't like the idea of 'String'.

As it is, I am still very biased towards C and biased against C++. Sparing details, much of what I work on fits C more (but it was a good exercise and a good way to make myself a. learn another language and b. try not be less biased against object/classes/etc which is maybe better stated as less closed-minded, less arrogant, and more accepting.). But what is useful is what some already suggested: I do indeed use list (it is fairly generic, is it not ?), and sort (same thing) to name two that would cause a name clash if I were to do using namespace std;, and so to that end I prefer being specific, in control and knowing that if I intend it to be the standard use then I will have to specify it. Put simply: no assuming allowed.

And as for making Boost's regex part of std. I do that for future integration and – again, I admit fully this is bias - I don't think it is as ugly as boost::regex:: .... Indeed, that is another thing for me. There are many things in C++ that I still have yet to come to fully accept in looks and methods (another example: variadic templates versus var arguments [though I admit variadic templates are very very useful!]). Even those that I do accept it was difficult, and I still have issues with them.

8 EngineDev Aug 21 2016 at 05:55

From my experiences, if you have multiple libraries that uses say, cout, but for a different purpose you may use the wrong cout.

For example, if I type in, using namespace std; and using namespace otherlib; and type just cout (which happens to be in both), rather than std::cout (or 'otherlib::cout'), you might use the wrong one, and get errors. It's much more effective and efficient to use std::cout.

8 SwissFrank May 23 2019 at 05:05

It's case by case. We want to minimize the "total cost of ownership" of the software over its lifespan. Stating "using namespace std" has some costs, but not using it also has a cost in legibility.

People correctly point out that when using it, when the standard library introduces new symbols and definitions, your code ceases to compile, and you may be forced to rename variables. And yet this is probably good long-term, since future maintainers will be momentarily confused or distracted if you're using a keyword for some surprising purpose.

You don't want to have a template called vector, say, which isn't the vector known by everyone else. And the number of new definitions thus introduced in the C++ library is small enough it may simply not come up. There is a cost to having to do this kind of change, but the cost is not high and is offset by the clarity gained by not using std symbol names for other purposes.

Given the number of classes, variables, and functions, stating std:: on every one might fluff up your code by 50% and make it harder to get your head around. An algorithm or step in a method that could be taken in on one screenful of code now requires scrolling back and forth to follow. This is a real cost. Arguably it may not be a high cost, but people who deny it even exists are inexperienced, dogmatic, or simply wrong.

I'd offer the following rules:

  1. std is different from all other libraries. It is the one library everyone basically needs to know, and in my view is best thought of as part of the language. Generally speaking there is an excellent case for using namespace std even if there isn't for other libraries.

  2. Never force the decision onto the author of a compilation unit (a .cpp file) by putting this using in a header. Always defer the decision to the compilation unit author. Even in a project that has decided to use using namespace std everywhere may fine a few modules that are best handled as exceptions to that rule.

  3. Even though the namespace feature lets you have many modules with symbols defined the same, it's going to be confusing to do so. Keep the names different to the extent possible. Even if not using the namespace feature, if you have a class named foo and std introduces a class named foo, it's probably better long-run to rename your class anyway.

  4. An alternative to using namespaces is to manually namespace symbols by prefixing them. I have two libraries I've used for decades, both starting as C libraries, actually, where every symbol is prefixed with "AK" or "SCWin". Generally speaking, this is like avoiding the "using" construct, but you don't write the twin colons. AK::foo() is instead AKFoo(). It makes code 5-10% denser and less verbose, and the only downside is that you'll be in big trouble if you have to use two such libraries that have the same prefixing. Note the X Window libraries are excellent in this regard, except they forgot to do so with a few #defines: TRUE and FALSE should have been XTRUE and XFALSE, and this set up a namespace clash with Sybase or Oracle that likewise used TRUE and FALSE with different values! (ASCII 0 and 1 in the case of the database!) One special advantage of this is that it applies seemlessly to preprocessor definitions, whereas the C++ using/namespace system doesn't handle them. A nice benefit of this is that it gives an organic slope from being part of a project to eventually being a library. In a large application of mine, all window classes are prefixed Win, all signal-processing modules Mod, and so on. There's little chance of any of these being reused so there's no practical benefit to making each group into a library, but it makes obvious in a few seconds how the project breaks into sub-projects.

7 AugustKarlstrom Apr 11 2013 at 21:22

With unqualified imported identifiers you need external search tools like grep to find out where identifiers are declared. This makes reasoning about program correctness harder.

7 MathGladiator Sep 21 2009 at 10:15

It depends on where it is located. If it is a common header, then you are diminishing the value of the namespace by merging it into the global namespace. Keep in mind, this could be a neat way of making module globals.

7 adn.911 Nov 30 2017 at 23:24

This is a bad practice, often known as global namespace pollution. Problems may occur when more than one namespace has the same function name with signature, then it will be ambiguous for the compiler to decide which one to call and this all can be avoided when you are specifying the namespace with your function call like std::cout . Hope this helps. :)

6 NoneyoGetit Jun 28 2013 at 03:33

To answer your question I look at it this way practically: a lot of programmers (not all) invoke namespace std. Therefore one should be in the habit of NOT using things that impinge or use the same names as what is in the namespace std. That is a great deal granted, but not so much compared to the number of possible coherent words and pseudonyms that can be come up with strictly speaking.

I mean really... saying "don't rely on this being present" is just setting you up to rely on it NOT being present. You are constantly going to have issues borrowing code snippets and constantly repairing them. Just keep your user-defined and borrowed stuff in limited scope as they should be and be VERY sparing with globals (honestly globals should almost always be a last resort for purposes of "compile now, sanity later"). Truly I think it is bad advice from your teacher because using std will work for both "cout" and "std::cout" but NOT using std will only work for "std::cout". You will not always be fortunate enough to write all your own code.

NOTE: Don't focus too much on efficiency issues until you actually learn a little about how compilers work. With a little experience coding you don't have to learn that much about them before you realize how much they are able to generalize good code into something something simple. Every bit as simple as if you wrote the whole thing in C. Good code is only as complex as it needs to be.