ใช้ `use` ใน C ++ หรือหลีกเลี่ยง


17

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

นอกจากนี้ฉันควรจะชอบ::std::หรือstd::?

  1. ระดับเนมสเปซusing namespace:

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  2. ชัดเจนอย่างสมบูรณ์:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
    
  3. ระดับเนมสเปซโดยใช้การประกาศ:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  4. ฟังก์ชั่นท้องถิ่นประกาศใช้:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
    
  5. ฟังก์ชั่นท้องถิ่นusing namespace:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
    
  6. อื่น ๆ อีก?

นี่คือการสมมติว่า pre-C ++ 14 และดังนั้นจึงไม่มีการใช้ชนิดการautoคืนสินค้า


2
ดูstackoverflow.com/questions/1265039/using-std-namespaceสำหรับจุดเริ่มต้น
AProgrammer

@AProgrammer: อาขอบคุณสำหรับลิงค์ที่ตอบคำถามของฉัน :) ยังคงสงสัยเกี่ยว::std::กับstd::ว่า
user541686

4
ฉันใช้stdโดยไม่คิดว่าสอง บางคนกำลังกำหนดเนมสเปซ std กำลังถามถึงปัญหา (และอาจกำลังค้นหาเพื่อใช้ประโยชน์ที่คนส่วนใหญ่ใช้stdและไม่ใช่::std)
AProgrammer

คำตอบ:


25

หลีกเลี่ยงการใช้usingในส่วนหัวเพราะนั่นทำลายวัตถุประสงค์ของเนมสเปซ

มันก็โอเคที่จะใช้มันในไฟล์ต้นฉบับ แต่ฉันจะยังคงหลีกเลี่ยงมันในบางกรณี (ตัวอย่างusing std)

อย่างไรก็ตามหากคุณมีเนมสเปซซ้อนกันอยู่ก็ใช้ได้:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1 เป็นเรื่องที่น่าอัศจรรย์ว่ามีบทเรียนจำนวนมากและหลักสูตรวิทยาลัยเพียงแค่บอกให้คุณใช้usingคำหลักโดยไม่มีคำอธิบายอย่างละเอียดว่าทำไม namespaces จึงถูกใช้เพื่อเริ่มต้นด้วย
เจฟฟรีย์สวีนีย์

ผู้คนต้องการเริ่มต้นด้วยการใช้ iostreams, strings และอื่น ๆ พวกเขาไม่ต้องการที่จะพิมพ์ std :: ทุกครั้งที่พวกเขาต้องการที่จะใช้สิ่งใดหรือต้องจำไว้อีกส่วนหนึ่งของแผ่นสำเร็จรูปที่จะนำหน้ารหัสซึ่งจะทำให้เกิดข้อผิดพลาดน้อยกว่าที่เป็นประโยชน์หากพวกเขาลืมมัน . :(
Colen

สิ่งที่ต้องการ typedef std :: string sstring; เป็นทางเลือกหรือไม่?
Giorgio

1
@Colen: วิญญาณที่น่าสงสารเหล่านี้สามารถใช้using std::coutและเป็นเพื่อนได้ แต่มันไม่เหมือนกับcoutชื่อที่มีมานานมากแล้ว
Benjamin Bannier

1
หากคุณเป็นนักศึกษาในวันแรกของการเรียน "คลาส C ++ ครั้งแรกของฉัน" ก็เป็นอีกสิ่งหนึ่งที่อาจทำให้เกิดข้อผิดพลาดทางไวยากรณ์ที่คุณไม่เข้าใจ มันง่ายสำหรับเราที่จะคิดออกเพราะเรามีประสบการณ์ในการเขียนโปรแกรม แต่เมื่อคุณพยายามที่จะเรียนรู้ภาษามันเป็นอีกเรื่องที่คุณต้องกังวลเกี่ยวกับสิ่งที่คุณไม่ต้องการ
Colen

11

เมื่อวางคำสั่ง using ในไฟล์ต้นฉบับโปรดดึงสิ่งที่คุณต้องการ ตัวอย่างเช่น

using std::string;
using std::ostringstream;

ปัญหาที่นี่คือถ้าคุณทำ

using namespace std;

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


หรือมิฉะนั้นคุณสามารถusing namespaceอยู่ในขอบเขตของฟังก์ชันเพื่อหลีกเลี่ยงปัญหา
Tamás Szelei

2
@fish - ที่จริงแล้วการใช้ 'namespace' ในขอบเขตฟังก์ชั่นไม่ได้หลีกเลี่ยงปัญหามันแค่ จำกัด พื้นที่ที่สิ่งต่าง ๆ อาจผิดพลาดได้ และถ้าคุณวาง 'ใช้เนมสเปซ' ในทุกฟังก์ชั่นมันก็ไม่ได้แตกต่างไปจากการทำทั่วโลก
Michael Kohne

แม้ว่า C ++ จะอนุญาตให้หนึ่งประกาศประเภทในระดับฟังก์ชั่นมันไม่ได้เป็นเรื่องปกติ; นอกจากนั้นชื่อที่เป็นไปได้นั้นง่ายต่อการมองเห็นจากคอมไพเลอร์เอาท์พุต (แต่คุณถูกต้องที่นี่ไม่ได้ป้องกันสิ่งเหล่านั้น)
Tamás Szelei

2

ตามที่ VJovic บ่งชี้ห้ามใช้usingในไฟล์ส่วนหัว usingในไฟล์ส่วนหัวมีผลต่อหน่วยการคอมไพล์ปัจจุบัน (ไฟล์. cpp) ในรูปแบบที่ไฟล์ต้นฉบับอาจไม่ได้คาดหวัง

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


2
ตามความกังวลในทางปฏิบัติยกเว้นว่ารหัสของคุณแทนที่ชื่อที่ใช้กันทั่วไปฉันค่อนข้างจะเห็นusing namespace JoystickModuleจุดเริ่มต้นของไฟล์. cpp มากกว่าที่JoystickModule::แนบมากับทุกวัตถุตลอด
Alex P

@AlexP: นั่นเป็นวิธีที่ฉันทำ หนึ่งusingคำสั่งสำหรับเนมสเปซของฉันเองฉันกำลังทำงานอยู่และทุกอย่างจะยังคงเป็นเนมสเปซอยู่
Benjamin Kloster

ฉันควรทำอย่างละเอียดเกี่ยวกับ "ใช้สัญลักษณ์เฉพาะจากเนมสเปซ" แทนที่จะนำหน้าสัญลักษณ์แต่ละตัวในทุกการใช้งานซึ่งไม่ได้ช่วยในการอ่านได้ฉันต้องการใช้การยกสัญลักษณ์อย่างชัดเจน using SomeNameSpace::SomeSymbol. วิธีนี้จะหลีกเลี่ยงการเคลื่อนย้ายสัญลักษณ์ทั้งหมดจากเนมสเปซไปยังขอบเขตปัจจุบัน
Bill Door

0

การเขียนusingส่วนหัวเป็นวิธีที่ดีที่สุดในการสร้างข้อบกพร่องที่น่ารังเกียจและเป็นไปไม่ได้ทุกประเภท อย่าได้ทำเช่นนี้

การเขียนusing namespace XYZในไฟล์ต้นฉบับนั้นดีขึ้นเล็กน้อย แต่ก็ยังทำให้คุณปวดหัวได้นับไม่ถ้วน วิธีที่ปลอดภัยคือการ explicitely using Foo::Barระบุสิ่งที่คุณกำลังใช้เช่น

สมมติว่าคุณมี Bar.cpp ดังต่อไปนี้:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

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

ในที่สุดคุณค้นพบสาเหตุ:
คุณ (ทางอ้อม) รวมFoo.hบางแห่ง ในไฟล์สำหรับเนมสเปซ Foo มีการเพิ่มฟังก์ชั่นใหม่:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

ซึ่งเป็นการจับคู่ที่ดีincrement(int)กว่าฟังก์ชั่นของคุณincrement(double)- ดังนั้นตอนนี้Foo::increment()ฟังก์ชั่นจะถูกเรียกใช้Bar::someFunction()แทน อ๊ะ

(และถ้าคุณต้องเขียนusingในส่วนหัวที่using namespace Fooอาจจะดีที่ใดก็ได้ในต้นไม้รวมของคุณ ... )

ดังนั้น ... อย่าเขียนusingส่วนหัวและระวังการเขียนลงusing namespaceในไฟล์ต้นฉบับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.