Tại sao là sử dụng không gian tên std; coi hành vi xấu?


2640

Tôi đã được người khác nói rằng viết using namespace std;mã là sai và thay vào đó tôi nên sử dụng std::coutstd::cintrực tiếp.

Tại sao được using namespace std;coi là một thực hành xấu? Là nó không hiệu quả hay nó có nguy cơ khai báo các biến mơ hồ (các biến có cùng tên với một hàm trong stdkhông gian tên)? Nó có ảnh hưởng đến hiệu suất?


512
Đừng quên bạn có thể làm: "bằng cách sử dụng std :: cout;" điều đó có nghĩa là bạn không phải gõ std :: cout, nhưng không mang vào toàn bộ không gian tên std cùng một lúc.
Hóa đơn

2
@a trả tiền mọt sách google-styleguide.googlecode.com/svn/trunk/ Liên kết không hoạt động nữa. Có vẻ như liên kết mới là google.github.io/styleguide/cppguide.html#Other_C++_Features
MCG

64
Điều đặc biệt xấu khi sử dụng 'sử dụng không gian tên std' ở phạm vi tệp trong các tệp tiêu đề. Sử dụng nó trong các tệp nguồn (* .cpp) ở phạm vi tệp sau khi bao gồm tất cả không quá tệ, vì hiệu ứng của nó bị giới hạn trong một đơn vị dịch thuật. Thậm chí ít vấn đề hơn là sử dụng nó bên trong các hàm hoặc các lớp, bởi vì tác dụng của nó bị giới hạn trong phạm vi hàm hoặc lớp.
sh-

5
Tôi sẽ không khuyến khích sử dụng sử dụng chỉ thị nhưng đối với không gian tên cụ thể như std::literals::chrono_literals, Poco::Data:Keywords, Poco::Unitsvà các công cụ mà sẽ đối phó với literals hoặc thủ đoạn dễ đọc. Bất cứ khi nào nó là trong các tập tin tiêu đề hoặc thực hiện. Tôi có thể ổn trong phạm vi chức năng tôi đoán, nhưng ngoài nghĩa đen và công cụ, nó không hữu ích.
Ludovic Zenohate Lagouardette

7
@Jon: Cụ thể là không có gì để làm với không gian tên cụ thể. Sự nhấn mạnh của tôi có nghĩa là "ở phạm vi tệp trong tệp tiêu đề". Để đưa ra lời khuyên: Không sử dụng "sử dụng không gian tên" (std hoặc khác) ở phạm vi tệp trong tệp tiêu đề. Nó là OK để sử dụng nó trong các tập tin thực hiện. Xin lỗi vì sự mơ hồ.
sh-

Câu trả lời:


2230

Điều này không liên quan đến hiệu suất. Nhưng hãy xem xét điều này: bạn đang sử dụng hai thư viện có tên Foo và Bar:

using namespace foo;
using namespace bar;

Mọi thứ đều hoạt động tốt, và bạn có thể gọi Blah()từ Foo và Quux()từ Bar mà không gặp vấn đề gì. Nhưng một ngày nào đó bạn nâng cấp lên phiên bản mới của Foo 2.0, giờ đây cung cấp một chức năng được gọi là Quux(). Bây giờ bạn đã có một cuộc xung đột: Cả Foo 2.0 và Bar nhập Quux()vào không gian tên toàn cầu của bạn. Điều này sẽ mất một số nỗ lực để khắc phục, đặc biệt là nếu các tham số chức năng xảy ra khớp.

Nếu bạn đã sử dụng foo::Blah()bar::Quux(), thì việc giới thiệu foo::Quux()sẽ là một sự kiện không.


435
Tôi luôn thích "nhập big_honkin_name là bhn" của Python để bạn có thể chỉ cần sử dụng "bhn.s Something" thay vì "big_honkin_name.s Something" - thực sự cắt giảm việc gõ. C ++ có cái gì như vậy không?
paxdiablo

764
Không gian tên @Pax io = boost :: filesystem;
AraK

152
Tôi nghĩ rằng đó là những điều cường điệu để nói rằng đó là "một số nỗ lực để khắc phục". Bạn sẽ không có trường hợp nào của foo :: Quux mới, vì vậy hãy phân biệt tất cả các mục đích sử dụng hiện tại của bạn với thanh :: Quux.
MattyT

289
Bất kỳ người nhạy cảm nào sẽ tạo ra một thư viện với các loại có tên không đủ tiêu chuẩn sẽ va chạm với các loại tiêu chuẩn?
erikkallen

94
@TomA: Vấn đề #definelà nó không giới hạn bản thân trong không gian tên, nhưng chà đạp lên toàn bộ cơ sở mã. Một bí danh không gian tên là những gì bạn muốn.
sbi

1391

Tôi đồng ý với tất cả những gì Greg viết , nhưng tôi muốn nói thêm: Nó thậm chí có thể trở nên tồi tệ hơn Greg đã nói!

Thư viện Foo 2.0 có thể giới thiệu một chức năng, Quux()đó là một kết hợp tốt hơn rõ ràng cho một số cuộc gọi của bạn Quux()so với bar::Quux()mã của bạn được gọi trong nhiều năm. Sau đó, của bạn vẫn biên dịch , nhưng nó âm thầm gọi hàm sai và không biết chúa là gì. Điều đó tồi tệ như mọi thứ có thể nhận được.

Hãy ghi nhớ rằng stdkhông gian tên có tấn số nhận dạng, nhiều trong số đó là rất cái chung (nghĩ list, sort, string, iterator, vv) mà rất có khả năng xuất hiện trong mã khác nữa.

Nếu bạn cho rằng điều này không thể xảy ra: Có một câu hỏi được đặt ra ở đây trên Stack Overflow, nơi chính xác điều này đã xảy ra (hàm sai gọi là do std::tiền tố bị bỏ qua ) khoảng nửa năm sau khi tôi đưa ra câu trả lời này. Đây là một ví dụ khác, gần đây hơn của một câu hỏi như vậy. Vì vậy, đây là một vấn đề thực sự.


Đây là một điểm dữ liệu nữa: Nhiều, nhiều năm trước, tôi cũng từng thấy khó chịu khi phải thêm tiền tố vào mọi thứ từ thư viện chuẩn std::. Sau đó, tôi đã làm việc trong một dự án nơi quyết định ban đầu rằng cả hai usingchỉ thị và tuyên bố đều bị cấm ngoại trừ phạm vi chức năng. Đoán xem cái gì? Hầu hết chúng ta mất vài tuần để làm quen với việc viết tiền tố và sau một vài tuần nữa, hầu hết chúng ta thậm chí đồng ý rằng nó thực sự làm cho mã dễ đọc hơn . Có một lý do cho điều đó: Cho dù bạn thích văn xuôi ngắn hơn hay dài hơn là chủ quan, nhưng các tiền tố khách quan làm tăng thêm sự rõ ràng cho mã. Không chỉ trình biên dịch, mà cả bạn, cũng thấy dễ dàng hơn để xem định danh nào được nhắc đến.

Trong một thập kỷ, dự án đó đã phát triển để có vài triệu dòng mã. Vì các cuộc thảo luận này lặp đi lặp lại, tôi đã từng tò mò về mức độ thường xuyên phạm vi chức năng (được phép) usingthực sự được sử dụng trong dự án. Tôi đã tìm các nguồn cho nó và chỉ tìm thấy một hoặc hai chục địa điểm được sử dụng. Đối với tôi điều này chỉ ra rằng, một khi đã thử, các nhà phát triển không thấy std::đủ đau đớn khi sử dụng các chỉ thị ngay cả sau mỗi 100 kLoC ngay cả khi nó được phép sử dụng.


Điểm mấu chốt: Hoàn toàn tiền tố mọi thứ không gây hại gì, mất rất ít thời gian để làm quen và có những lợi thế khách quan. Cụ thể, nó làm cho mã dễ hiểu hơn bởi trình biên dịch và bởi các trình đọc của con người - và đó có lẽ nên là mục tiêu chính khi viết mã.


140
Nó làm hại đáng kể mật độ mã bạn có thể đóng gói trong một dòng duy nhất. Bạn cuối cùng viết mã của bạn theo một cách rất dài; làm giảm khả năng đọc. Cá nhân, tôi nghĩ rằng mã ngắn hơn (nhưng không quá ngắn) có xu hướng dễ đọc hơn (vì có ít nội dung để đọc và ít nội dung hơn để bị phân tâm).
Lie Ryan

92
Đoán bạn đã bỏ lỡ ngày xưa trước khi C ++ có một stringlớp tiêu chuẩn , và dường như mọi thư viện đều có cái riêng của họ. Nói cho bạn biết: Chúng tôi sẽ tiếp tục viết mã của chúng tôi std::và bạn có thể chạy mã của chúng tôi grep -v std:: | vimkhi bạn duyệt mã. Hoặc bạn có thể dạy cho biên tập viên của mình đó std::là một từ khóa được tô màu giống như màu nền. Dù làm việc gì.
Mike DeSimone

80
Tôi không nghĩ std::là có hại gì cả. Nó mang thông tin rất quan trọng (cụ thể là "bất cứ thứ gì đến sau là một phần của thư viện chuẩn" và nó vẫn là một tiền tố khá ngắn và gọn. Hầu hết, đôi khi, không có vấn đề gì cả. Đôi khi, bạn có một vài dòng mã nơi bạn cần phải tham khảo những biểu tượng cụ thể trong stdkhông gian tên rất nhiều, và sau đó một using. tuyên bố trong đó phá được phạm vi đặc biệt là vấn đề độc đáo Nhưng trong trường hợp tổng quát, nó không phải là tiếng ồn, nó truyền tải thông tin có giá trị ngoài để mập mờ loại bỏ.
jalf

147
Bất cứ khi nào tôi nhìn thấy std::, tôi biết nó sẽ đến từ std::mà không phải suy nghĩ về nó. Nếu tôi thấy stringhay listhay mapbởi bản thân, tôi tự hỏi một chút.
Mateen Ulhaq

68
@LieRyan Sau đó, chúc may mắn viết một thư viện hình học mà không bao giờ đặt tên một cái gì đó vector, transformhoặc distance. Và đó chỉ là những ví dụ về rất nhiều cái tên rất phổ biến được sử dụng trong thư viện tiêu chuẩn. Đề xuất không sử dụng chúng vì sợ hãi hoặc ý kiến ​​thiên vị về tính năng không gian tên là một phần không thể thiếu của C ++ khá phản tác dụng.
Christian Rau

420

Vấn đề với việc đưa using namespacevào các tệp tiêu đề của các lớp của bạn là nó buộc bất kỳ ai muốn sử dụng các lớp của bạn (bằng cách bao gồm các tệp tiêu đề của bạn) cũng phải 'sử dụng' (tức là nhìn thấy mọi thứ trong) các không gian tên đó.

Tuy nhiên, bạn có thể cảm thấy thoải mái khi đặt câu lệnh sử dụng trong các tệp (riêng tư) * .cpp của mình.


Xin lưu ý rằng một số người không đồng ý với câu nói "cảm thấy thoải mái" của tôi như thế này - bởi vì mặc dù một usingtuyên bố trong tệp cpp tốt hơn trong tiêu đề (vì nó không ảnh hưởng đến những người bao gồm tệp tiêu đề của bạn), nhưng họ nghĩ rằng nó vẫn không tốt (vì tùy thuộc vào mã, nó có thể làm cho việc thực hiện lớp khó khăn hơn để duy trì). Mục C-Super Super FAQ này cho biết,

Lệnh sử dụng tồn tại cho mã C ++ cũ và để dễ dàng chuyển sang không gian tên, nhưng có lẽ bạn không nên sử dụng nó một cách thường xuyên, ít nhất là không phải trong mã C ++ mới của bạn.

Câu hỏi thường gặp gợi ý hai lựa chọn thay thế:

  • Một khai báo sử dụng:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Chỉ cần gõ std ::

    std::cout << "Values:";

1
Tất nhiên, bạn cũng không bao giờ nên giả sử trạng thái của cout toàn cầu, vì sợ ai đó có std: cout << std :: hex và thất bại với std :: restore_cout_state sau đó. Nhưng đó là một fatberg hoàn toàn khác.
Móż

233

Gần đây tôi đã gặp phải một khiếu nại về Visual Studio 2010 . Hóa ra khá nhiều tập tin nguồn có hai dòng này:

using namespace std;
using namespace boost;

Rất nhiều tính năng Boost đang đi vào tiêu chuẩn C ++ 0x và Visual Studio 2010 có rất nhiều tính năng C ++ 0x, vì vậy đột nhiên các chương trình này không được biên dịch.

Do đó, tránh using namespace X;là một hình thức chứng minh trong tương lai, một cách đảm bảo thay đổi thư viện và / hoặc các tệp tiêu đề đang sử dụng sẽ không phá vỡ chương trình.


14
Điều này. Boost và std có rất nhiều sự trùng lặp - đặc biệt là từ C ++ 11.
einpoklum

1
Tôi đã làm điều đó một lần và học một bài học một cách khó khăn. Bây giờ tôi không bao giờ sử dụng usingbên ngoài một định nghĩa chức năng và hiếm khi sử dụng using namespacecả.
Ferruccio

210

Phiên bản ngắn: không sử dụng usingkhai báo toàn cầu hoặc chỉ thị trong tệp tiêu đề. Hãy sử dụng chúng trong các tập tin thực hiện. Dưới đây là những gì Herb SutterAndrei Alexandrescu nói về vấn đề này trong Tiêu chuẩn mã hóa C ++ (được nhấn mạnh là của tôi):

Tóm lược

Việc sử dụng không gian tên là để thuận tiện cho bạn, không phải để bạn gây ra cho người khác: Không bao giờ viết một tuyên bố sử dụng hoặc chỉ thị sử dụng trước một lệnh #incoide.

Hệ quả: Trong các tệp tiêu đề, không viết mức không gian tên bằng cách sử dụng các lệnh hoặc sử dụng khai báo; thay vào đó, rõ ràng không gian tên đủ điều kiện tất cả các tên. (Quy tắc thứ hai tuân theo quy tắc thứ nhất, bởi vì các tiêu đề không bao giờ có thể biết những tiêu đề nào khác có thể xuất hiện sau chúng.)

Thảo luận

Tóm lại: Bạn có thể và nên sử dụng không gian tên bằng cách sử dụng các khai báo và chỉ thị một cách tự do trong các tệp triển khai của mình sau các lệnh #incoide và cảm thấy tốt về nó. Mặc dù nhiều lần khẳng định ngược lại, không gian tên sử dụng khai báo và chỉ thị không phải là xấu xa và chúng không đánh bại mục đích của không gian tên. Thay vào đó, chúng là những gì làm cho không gian tên có thể sử dụng .


4
Chỉ cần thêm một ý kiến ​​của lập trình viên ở đây, nhưng trong khi tôi đồng ý 100% với tuyên bố rằng từ đó usingsẽ không bao giờ xuất hiện trong tiêu đề, tôi không tin về giấy phép miễn phí đặt using namespace xyz;bất cứ nơi nào trong mã của bạn, đặc biệt là nếu xyzstd. Tôi sử dụng using std::vector;biểu mẫu, vì điều đó chỉ kéo một yếu tố duy nhất từ ​​không gian tên vào phạm vi toàn cầu giả, do đó dẫn đến ít nguy cơ va chạm hơn.
thức

2
@Lightness Races in Orbit bạn tất nhiên được quyền theo ý kiến ​​của bạn. Sẽ hữu ích hơn nếu có một số nỗ lực giải thích lý do tại sao bạn không đồng ý với lời khuyên được đưa ra trong câu trả lời này. Đặc biệt sẽ rất thú vị để hiểu điểm của không gian tên là gì nếu 'sử dụng' chúng là xấu? Tại sao không chỉ đặt tên cho std_cout thay vì std :: cout ... những người tạo ra C ++ / không gian tên phải có một số ý tưởng khi họ bận tâm tạo ra chúng.
nyholku

1
@nyholku: Không cần - phần lớn các câu trả lời khác đưa ra lý do tương tự tôi sẽ làm. Ngoài ra xin vui lòng không ngần ngại ghi chú ":)" Tôi đã thêm vào nhận xét của mình! Và tôi đã không nói không gian tên là xấu.
Các cuộc đua nhẹ nhàng trong quỹ đạo

Vâng, tôi nhận thấy rằng :) nhưng IMO phần lớn câu trả lời (đi ngược lại lời khuyên hiền triết này) là sai lầm (không phải là tôi đã thực hiện bất kỳ số liệu thống kê nào là đa số bây giờ). Nếu bạn đồng ý rằng không gian tên là 'không tệ' thì bạn có thể nói bạn nghĩ chúng phù hợp ở đâu nếu bạn không đồng ý với câu trả lời này?
nyholku

Tôi không thể giúp nhưng cảm thấy đó using namespacelà xấu xa như gotolà xấu xa. Cả hai đều có cách sử dụng hợp lệ, nhưng 999 lần trong số 1000 chúng sẽ bị sử dụng sai. Vì vậy, yeah, với using namespacenguồn bạn sẽ không làm ô nhiễm không gian tên của người khác bao gồm, gọn gàng. Nhưng nó vẫn không bảo vệ bạn trước "niềm vui" phát sinh từ using namespace Foo+ using namespace Barkhi bạn gọi (ẩn Foo: :) baz(xyz)và đột nhiên mã bị phá vỡ (không có thay đổi liên quan) chỉ vì Bar::baz()được thêm vào ở đâu đó, điều này xảy ra tốt hơn trận đấu (và do đó bây giờ được gọi thay thế)
CharonX

122

Không nên sử dụng usingchỉ thị ở phạm vi toàn cầu, đặc biệt là trong các tiêu đề. Tuy nhiên, có những tình huống phù hợp ngay cả trong tệp tiêu đề:

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

Điều này tốt hơn trình độ rõ ràng ( std::sin, std::cos...), vì nó ngắn hơn và có khả năng làm việc với các loại dấu phẩy động do người dùng xác định (thông qua tra cứu phụ thuộc đối số (ADL)).


9
Tôi xin lỗi, nhưng tôi hoàn toàn không đồng ý với điều này.
Billy ONeal

4
@Billy: Không có cách nào khác để hỗ trợ gọi userlib :: cos (userlib :: superint). Mỗi tính năng có một công dụng.
Zan Lynx

17
@Zan: Tất nhiên là có. using std::cos;, using std::sinVv Vấn đề này mặc dù là bất kỳ cũng được thiết kế userlibsẽ có của họ sincosbên trong không gian tên riêng của họ là tốt, vì vậy đây thực sự không giúp bạn. (Trừ khi có using namespace userlibtrước mẫu này và nó cũng tệ như using namespace std- và phạm vi không bị giới hạn.) Hơn nữa, chức năng duy nhất như thế này tôi từng thấy điều này xảy ra là swap, và trong những trường hợp như vậy tôi sẽ khuyên bạn chỉ nên tạo mẫu chuyên môn hóa std::swapvà tránh toàn bộ vấn đề.
Billy ONeal

11
@BillyONeal: template<typename T> void swap(MyContainer<T>&, MyContainer<T>&)(Không có chuyên môn hóa một phần mẫu chức năng (FTPS), vì vậy đôi khi bạn cần phải dùng đến quá tải thay thế.
sbi

38
@BillyONeal: Nhận xét (7 lần nâng cấp!) Của bạn là sai - tình huống bạn mô tả chính xác là những gì ADL được thiết kế để bao quát. Tóm lại, nếu xcó một hoặc nhiều "không gian tên liên quan đến" (ví dụ như nếu nó được định nghĩa trong namespace userlib) sau đó bất kỳ chức năng cuộc gọi mà trông giống như cos(x)sẽ bổ sung tìm trong những không gian tên - mà không cần bất kỳ using namespace userlib;trước là cần thiết. Zan Lynx đã đúng (và tra cứu tên C ++ là byzantine ...)
j_random_hacker

97

Không sử dụng nó trên toàn cầu

Nó được coi là "xấu" chỉ khi được sử dụng trên toàn cầu . Bởi vì:

  • Bạn làm lộn xộn không gian tên bạn đang lập trình.
  • Người đọc sẽ gặp khó khăn khi xem một định danh cụ thể đến từ đâu, khi bạn sử dụng nhiều using namespace xyz.
  • Bất cứ điều gì đúng với những người đọc khác về mã nguồn của bạn thậm chí còn đúng hơn đối với người đọc thường xuyên nhất về nó: chính bạn. Trở lại sau một hoặc hai năm và xem ...
  • Nếu bạn chỉ nói về using namespace stdbạn có thể không nhận thức được tất cả những thứ bạn lấy - và khi bạn thêm cái khác #includehoặc chuyển sang bản sửa đổi C ++ mới, bạn có thể gặp phải xung đột tên mà bạn không biết.

Bạn có thể sử dụng nó cục bộ

Đi trước và sử dụng nó một cách tự do (gần như). Điều này, tất nhiên, ngăn bạn khỏi sự lặp lại std::- và sự lặp lại cũng tệ.

Một thành ngữ để sử dụng nó cục bộ

Trong C ++ 03 có một thành ngữ - mã soạn sẵn - để thực hiện một swapchức năng cho các lớp của bạn. Có ý kiến ​​cho rằng bạn thực sự sử dụng một địa phương using namespace std- hoặc ít nhất là 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(...)`
}

Điều này thực hiện phép thuật sau:

  • Trình biên dịch sẽ chọn std::swapfor value_, tức là void std::swap(int, int).
  • Nếu bạn có quá tải void swap(Child&, Child&)thực hiện trình biên dịch sẽ chọn nó.
  • Nếu bạn không có quá tải, trình biên dịch sẽ sử dụng void std::swap(Child&,Child&)và thử trao đổi tốt nhất.

Với C ++ 11, không có lý do gì để sử dụng mẫu này nữa. Việc thực hiện std::swapđã được thay đổi để tìm một sự quá tải tiềm năng và chọn nó.


5
"Việc thực hiện std :: exchange đã được thay đổi để tìm ra sự quá tải tiềm năng và chọn nó." - Gì? Bạn có chắc chắn về điều đó không? Mặc dù sự thật là việc cung cấp một tùy chỉnh swapở nơi đầu tiên không còn quan trọng trong C ++ 11 nữa, vì std::swapbản thân nó linh hoạt hơn (sử dụng ngữ nghĩa di chuyển). Nhưng std::swaptự động chọn trao đổi tùy chỉnh của riêng bạn, điều đó hoàn toàn mới đối với tôi (và tôi không thực sự tin vào điều đó).
Christian Rau

@ChristianRau Tôi nghĩ vậy, vâng. Tôi đọc nó trên SO ở đâu đó. Chúng ta luôn có thể hỏi Howard , anh ta nên biết. Tôi đang đàođào bây giờ ...
Towi

14
Ngay cả trong trường hợp hoán đổi, thành ngữ rõ ràng hơn (và rất may là phổ biến hơn) là viết using std::swap;chứ không phải using namespace std;. Thành ngữ cụ thể hơn có ít tác dụng phụ hơn và do đó làm cho mã dễ duy trì hơn.
Adrian McCarthy

11
Câu cuối cùng là sai. Trong C ++ 11 Swap Std Two Step đã chính thức thiên nhiên ưu đãi như đúng cách để gọi swap, và nhiều nơi khác trong tiêu chuẩn đã được thay đổi để nói họ gọi swapnhư thế (NB như đã nêu ở trên, using std::swaplà một cách đúng đắn, không using namespace std). Nhưng std::swapbản thân nó đã không thay đổi để tìm một số khác swapvà sử dụng nó. Nếu std::swapđược gọi, sau đó std::swapđược sử dụng.
Jonathan Wakely 16/07/2015

3
Có thể khôn ngoan hơn khi chỉ gõ using std::swapcục bộ, để giảm không gian tên cục bộ đồng thời tạo mã tự ghi. Bạn hiếm khi quan tâm đến toàn bộ không gian tên std, vì vậy hãy chọn ra những phần bạn quan tâm.
Lundin

79

Nếu bạn nhập các tập tin tiêu đề phải bạn đột nhiên có những cái tên như hex, left, plushoặc counttrong phạm vi toàn cầu của bạn. Điều này có thể gây ngạc nhiên nếu bạn không biết std::có chứa những tên này. Nếu bạn cũng cố gắng sử dụng những tên này cục bộ, nó có thể dẫn đến một số nhầm lẫn.

Nếu tất cả các công cụ tiêu chuẩn nằm trong không gian tên riêng của nó, bạn không phải lo lắng về xung đột tên với mã của bạn hoặc các thư viện khác.


12
+1 chưa kể distance. Tôi vẫn thích những cái tên không đủ điều kiện bất cứ nơi nào có khả năng thực tế, vì điều đó làm tăng khả năng đọc cho tôi. hơn nữa, tôi nghĩ rằng thực tế là chúng ta thường không đủ điều kiện trong lời nói và sẵn sàng dành thời gian để giải quyết sự mơ hồ có thể, có nghĩa là nó có giá trị để có thể hiểu những gì người ta đang nói về mà không cần bằng cấp và áp dụng vào nguồn mã có nghĩa là nó được cấu trúc theo cách mà nó rõ ràng tất cả những gì về nó ngay cả khi không có bằng cấp.
Chúc mừng và hth. - Alf

Mặc dù vậy, công bằng mà nói, bạn không có hầu hết những thứ đó nếu bạn không bao gồm <iomanip>. Tuy nhiên, điểm tốt.
einpoklum

48

Một lý do khác là bất ngờ.

Nếu tôi thấy cout << blah, thay vì std::cout << blahtôi nghĩ: đây là coutgì? Có phải là bình thường cout? Nó có gì đặc biệt không?


25
Đây co phải la một tro đua? Tôi thực sự không thể nói. Nếu không thì cá nhân tôi sẽ cho rằng đó là 'cout' bình thường trừ khi bạn không tin tưởng mã vì nếu không đó sẽ là mùi mã BEYOND MAJOR, IMO. ... Và nếu bạn không tin tưởng mã thì tại sao bạn lại sử dụng nó ngay từ đầu? Lưu ý rằng tôi không nói "TRUST EvERYThING !!" nhưng điều này cũng có vẻ hơi xa vời nếu bạn, nói, giao dịch với một thư viện nổi tiếng từ GitHub hoặc một cái gì đó.
Brent Rittenhouse

28
@BrentRittenhouse coutlà một ví dụ tồi vì mọi người đều nhận ra điều đó. Nhưng hãy tưởng tượng futuretrong một ứng dụng tài chính. Đây có phải là hợp đồng mua hoặc bán một cái gì đó vào một ngày nhất định không? Không, không. Nếu mã nói rằng std::futurebạn sẽ không dễ bị nhầm lẫn.
James Hollis

2
@BrentRittenhouse có thể là một ví dụ tồi tệ, có ít nhất bốn thư viện khác nhau có cout. Có thể là "nó là thư viện chuẩn? Libstdc ++? Stl? Cái gì khác?" Và không, không phải ai cũng biết std :: cout, ít nhất là vốn có, 6 trong số 7 công nhân mới mà chúng tôi không nhận được. Bởi vì chương trình giáo dục không sử dụng những người trong giáo dục. Tôi phải đuổi đi printfs. Hoặc gỡ lỗi () - từ Qt.
Swift - Thứ Sáu ngày

1
Có thật không? Đó là khá nhiều trong ví dụ đầu tiên của chương đầu tiên về nhiều cuốn sách về C ++, nếu bất cứ điều gì nó (với cách sử dụng toán tử chèn) là C ++ duy nhất mà một số cơ quan mới biết.
mckenzm

@mckenzm Tôi có thể đặt nó trong một cuốn sách hoặc ghi chú bài giảng để giảm bớt sự lộn xộn, nhưng không phải trong mã
Martin Beckett

45

Các lập trình viên có kinh nghiệm sử dụng bất cứ điều gì giải quyết vấn đề của họ và tránh bất cứ điều gì tạo ra vấn đề mới và họ tránh các chỉ thị sử dụng cấp độ tệp tiêu đề vì lý do chính xác này.

Các lập trình viên có kinh nghiệm cũng cố gắng tránh trình độ đầy đủ của các tên trong các tệp nguồn của họ. Một lý do nhỏ cho điều này là việc viết thêm mã khi không đủ mã trừ khi có lý do chính đáng . Một lý do chính cho việc này là tắt tra cứu phụ thuộc vào đối số (ADL).

Những lý do tốt là gì? Đôi khi các lập trình viên rõ ràng muốn tắt ADL, những lần khác họ muốn định hướng.

Vì vậy, sau đây là OK:

  1. Chỉ thị sử dụng cấp độ chức năng và khai báo sử dụng bên trong triển khai chức năng
  2. Khai báo cấp độ nguồn tệp trong tệp nguồn
  3. (Đôi khi) chỉ thị sử dụng cấp độ tệp nguồn

43

Tôi đồng ý rằng nó không nên được sử dụng trên toàn cầu, nhưng nó không quá tệ khi sử dụng cục bộ, như trong a namespace. Đây là một ví dụ từ "Ngôn ngữ lập trình 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

}

Trong ví dụ này, chúng tôi đã giải quyết các xung đột tên tiềm năng và sự mơ hồ phát sinh từ thành phần của chúng.

Các tên được khai báo rõ ràng ở đó (bao gồm các tên được khai báo bằng cách sử dụng khai báo như His_lib::String) sẽ ưu tiên hơn các tên được truy cập trong phạm vi khác bằng cách sử dụng directive ( using namespace Her_lib).


29

Tôi cũng coi đó là một thực hành xấu. Tại sao? Chỉ một ngày, tôi nghĩ rằng chức năng của một không gian tên là phân chia công cụ, vì vậy tôi không nên làm hỏng nó bằng cách ném mọi thứ vào một túi toàn cầu.

Tuy nhiên, nếu tôi thường sử dụng 'cout' và 'cin', tôi viết: using std::cout; using std::cin;trong tệp .cpp (không bao giờ trong tệp tiêu đề như nó truyền bá #include). Tôi nghĩ rằng sẽ không có ai lành mạnh đặt tên cho một luồng couthay cin. ;)


7
Đó là một khai báo sử dụng cục bộ , một điều rất khác so với chỉ thị sử dụng .
sbi

25

Thật tuyệt khi thấy mã và biết những gì nó làm. Nếu tôi thấy std::couttôi biết đó là coutdòng stdthư viện. Nếu tôi thấy coutthì tôi không biết. Nó có thểcoutdòng của stdthư viện. Hoặc có thể có int cout = 0;mười dòng cao hơn trong cùng một chức năng. Hoặc một staticbiến có tên couttrong tập tin đó. Nó có thể là bất cứ điều gì.

Bây giờ, hãy lấy một triệu cơ sở mã dòng, không đặc biệt lớn và bạn đang tìm kiếm một lỗi, điều đó có nghĩa là bạn biết có một dòng trong một triệu dòng này không làm những gì nó phải làm. cout << 1;có thể đọc một cái static inttên cout, dịch nó sang trái một chút và ném đi kết quả. Tìm kiếm một lỗi, tôi phải kiểm tra xem. Bạn có thể thấy làm thế nào tôi thực sự thực sự thích nhìn thấy std::cout?

Đó là một trong những điều có vẻ là một ý tưởng thực sự tốt nếu bạn là một giáo viên và không bao giờ phải viết và duy trì bất kỳ mã nào để kiếm sống. Tôi thích xem mã ở đâu (1) Tôi biết nó làm gì; và, (2) Tôi tin tưởng rằng người viết nó biết nó làm gì.


4
Làm thế nào để bạn biết "std :: cout << 1" không đọc một int int có tên cout trong không gian tên std làm dịch chuyển nó theo một và ném đi kết quả? Ngoài ra, làm thế nào để bạn biết "<<" làm gì;) ??? ... có vẻ như câu trả lời này không phải là điểm dữ liệu tốt để tránh 'sử dụng'.
nyholku

4
Nếu ai đó đã xác định lại std :: cout là một số nguyên, thì vấn đề của bạn không phải là kỹ thuật, mà là xã hội - ai đó có nó cho bạn. (và có lẽ bạn cũng nên kiểm tra tất cả các tiêu đề để biết những thứ như #define đúng sai, v.v.)
Jeremy Friesner

2
Khi tôi nhìn thấy cout, tôi biết đó là std :: cout, luôn luôn. Nếu tôi sai, đó là vấn đề của người đã viết mã này, không phải tôi :)
Tien Do

22

Đó là tất cả về quản lý sự phức tạp. Sử dụng không gian tên sẽ kéo mọi thứ mà bạn không muốn, và do đó có thể khiến việc gỡ lỗi trở nên khó khăn hơn (tôi nói là có thể). Sử dụng std :: khắp nơi khó đọc hơn (nhiều văn bản hơn và tất cả những thứ đó).

Ngựa cho các khóa học - quản lý sự phức tạp của bạn như thế nào bạn có thể tốt nhất và cảm thấy có thể.


18

Xem xét

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


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

class stringstream {  // Uh oh
};

Lưu ý rằng đây là một ví dụ đơn giản. Nếu bạn có các tệp có 20 bao gồm và nhập khác, bạn sẽ có rất nhiều phụ thuộc để tìm ra vấn đề. Điều tồi tệ hơn về nó là bạn có thể nhận được các lỗi không liên quan trong các mô-đun khác tùy thuộc vào các định nghĩa xung đột.

Điều đó không kinh khủng, nhưng bạn sẽ tự cứu mình khỏi đau đầu bằng cách không sử dụng nó trong các tệp tiêu đề hoặc không gian tên toàn cầu. Có thể được phép làm điều đó trong phạm vi rất hạn chế, nhưng tôi chưa bao giờ gặp vấn đề khi gõ thêm năm ký tự để làm rõ chức năng của mình đến từ đâu.


18
  1. Bạn cần có khả năng đọc mã được viết bởi những người có phong cách khác nhau và ý kiến ​​thực hành tốt nhất so với bạn.

  2. Nếu bạn chỉ sử dụng cout, không ai bị nhầm lẫn. Nhưng khi bạn có rất nhiều không gian tên bay xung quanh và bạn thấy lớp này và bạn không chắc chắn chính xác nó làm gì, có không gian tên rõ ràng đóng vai trò như một nhận xét sắp xếp. Bạn có thể thấy ngay từ cái nhìn đầu tiên, "ồ, đây là một hoạt động của hệ thống tập tin" hoặc "đó là công cụ mạng".


17

Sử dụng nhiều không gian tên cùng một lúc rõ ràng là một công thức cho thảm họa, nhưng sử dụng không gian tên JUST stdvà chỉ không gian tên stdkhông phải là vấn đề lớn theo quan điểm của tôi bởi vì việc xác định lại chỉ có thể xảy ra bởi mã của riêng bạn ...

Vì vậy, chỉ cần xem chúng có chức năng như các tên dành riêng như "int" hoặc "class" và đó là nó.

Mọi người nên dừng việc quá hậu môn về nó. Giáo viên của bạn đã đúng tất cả cùng. Chỉ cần sử dụng MỘT không gian tên; đó là toàn bộ điểm của việc sử dụng không gian tên ở vị trí đầu tiên. Bạn không được phép sử dụng nhiều hơn một cùng một lúc. Trừ khi nó là của riêng bạn. Vì vậy, một lần nữa, xác định lại sẽ không xảy ra.


Tạo va chạm không phải là khó - chuỗi ngắn thích min, endlessxuất hiện trong std::không gian tên. Nhưng hơn nữa, bây giờ std::có hàng ngàn biểu tượng trong đó, người đọc có thể biết một biểu tượng mới mà họ có thể không biết đến từ đâu.
Tom Swirly

Không gian tên std tồn tại bởi vì mọi người, hoặc bạn, đồng nghiệp của bạn hoặc những người viết phần mềm trung gian bạn sử dụng, không phải lúc nào cũng khôn ngoan về việc đặt các chức năng bên trong các không gian tên. Do đó, bạn có thể nhập tất cả std :: và không có gì khác, trong khi vẫn tạo ra xung đột giữa, giả sử, std :: min và di sản của người khác :: min () từ trước khi nó còn ở std.
Trống Aiken

14

Tôi đồng ý với những người khác ở đây, nhưng tôi muốn giải quyết các mối quan tâm về khả năng đọc - bạn có thể tránh tất cả điều đó bằng cách sử dụng typedefs ở đầu tệp, hàm hoặc khai báo lớp.

Tôi thường sử dụng nó trong khai báo lớp của mình vì các phương thức trong một lớp có xu hướng xử lý các kiểu dữ liệu tương tự (các thành viên) và typedef là một cơ hội để gán một tên có ý nghĩa trong ngữ cảnh của lớp. Điều này thực sự hỗ trợ khả năng đọc trong các định nghĩa của các phương thức lớp.

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

và trong việc thực hiện:

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

như trái ngược với:

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

hoặc là:

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

Chỉ là một nhận xét nhỏ, trong khi typedef hữu ích, tôi sẽ xem xét việc tạo một lớp đại diện cho Lines thay vì sử dụng typedef.
Eyal Solnik

14

Một ví dụ cụ thể để làm rõ mối quan tâm. Hãy tưởng tượng bạn có một tình huống trong đó bạn có hai thư viện foobarmỗi thư viện có không gian tên riêng:

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

namespace bar {
    ...
}

Bây giờ hãy nói rằng bạn sử dụng foobarcùng nhau trong chương trình của riêng bạn như sau:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

Tại thời điểm này mọi thứ đều ổn. Khi bạn chạy chương trình của mình, 'Làm gì đó'. Nhưng sau đó, bạn cập nhật barvà giả sử nó đã thay đổi thành:

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

Tại thời điểm này, bạn sẽ gặp lỗi trình biên dịch:

using namespace foo;
using namespace bar;

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

Vì vậy, bạn sẽ cần thực hiện một số bảo trì để làm rõ nghĩa 'a' foo::a. Điều đó là không mong muốn, nhưng may mắn là nó khá dễ dàng (chỉ cần thêm foo::vào trước tất cả các cuộc gọi để atrình biên dịch đánh dấu là mơ hồ).

Nhưng hãy tưởng tượng một kịch bản thay thế nơi thanh thay đổi thay vào đó trông như thế này:

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

Tại thời điểm này, cuộc gọi của bạn a(42)đột nhiên liên kết với bar::athay vì foo::avà thay vì thực hiện "một cái gì đó", nó thực hiện "một cái gì đó hoàn toàn khác". Không có cảnh báo trình biên dịch hoặc bất cứ điều gì. Chương trình của bạn chỉ âm thầm bắt đầu làm một cái gì đó hoàn thành khác với trước đây.

Khi bạn sử dụng một không gian tên, bạn sẽ gặp rủi ro như một kịch bản như thế này, đó là lý do tại sao mọi người không thoải mái khi sử dụng các không gian tên. Càng nhiều thứ trong một không gian tên, nguy cơ xung đột càng lớn, do đó mọi người có thể còn khó chịu hơn khi sử dụng không gian tên std(do số lượng vật trong không gian tên đó) so với các không gian tên khác.

Cuối cùng, đây là sự đánh đổi giữa khả năng ghi và độ tin cậy / khả năng bảo trì. Khả năng đọc cũng có thể là yếu tố, nhưng tôi có thể thấy các đối số cho điều đó đi cả hai chiều. Thông thường tôi sẽ nói độ tin cậy và khả năng bảo trì là quan trọng hơn, nhưng trong trường hợp này bạn sẽ liên tục trả chi phí có thể ghi cho một tác động độ tin cậy / khả năng bảo trì khá hiếm. Sự đánh đổi 'tốt nhất' sẽ quyết định dự án của bạn và các ưu tiên của bạn.


Kịch bản thứ hai giành được thỏa thuận cho tôi. Không có không gian tên một lần nữa. Không thể có những thay đổi tinh tế như vậy trong chức năng sẽ không bị phát hiện dưới mui xe.
safe_malloc

13

Một không gian tên là một phạm vi được đặt tên. Không gian tên được sử dụng để nhóm các khai báo liên quan và để tách các mục riêng biệt. Ví dụ: hai thư viện được phát triển riêng biệt có thể sử dụng cùng một tên để chỉ các mục khác nhau, nhưng người dùng vẫn có thể sử dụng cả hai:

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
    // ...
}

Lặp lại một tên không gian tên có thể là một sự phân tâm cho cả người đọc và người viết. Do đó, có thể nói rằng các tên từ một không gian tên cụ thể có sẵn mà không cần bằng cấp rõ ràng. Ví dụ:

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
    // ...
}

Không gian tên cung cấp một công cụ mạnh mẽ để quản lý các thư viện khác nhau và các phiên bản mã khác nhau. Cụ thể, họ cung cấp các lựa chọn thay thế cho lập trình viên về cách rõ ràng để tạo một tham chiếu đến một tên không nhắm mục tiêu.

Nguồn: Tổng quan về ngôn ngữ lập trình C ++ của Bjarne Stroustrup


4
Rất thú vị khi một câu trả lời này dựa trên sự hướng dẫn từ người khác mà Bjarne Stroustrup đã kiếm được -2 ... cậu bé Bjarne phải là một lập trình viên nghèo và thiếu kinh nghiệm khi giới thiệu tính năng này vào C ++
nyholku

@nyholku: Xem này .
sbi

10

Một ví dụ trong đó using namespace stdđưa ra một lỗi biên dịch vì sự mơ hồ của số đếm, đây cũng là một hàm trong thư viện thuật toán.

#include <iostream>

using namespace std;

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

2
::count- giải quyết vấn đề. Thông thường, bạn sẽ có nhiều nội dung từ tên std hơn so với từ nơi khác, việc giữ nguyên lệnh sử dụng không gian tên có thể giúp bạn nhập.
PSkocik 11/07/2015

Vấn đề thực sự ở đây là C ++ vẫn có các không gian tên không gian. Điều này và thực tế là 'cái này' ẩn trong các phương thức, gây ra rất nhiều lỗi và vấn đề mà tôi thậm chí không thể đếm được, ngay cả với biến 'đếm' đúng. ;)
Trống Aiken

9

Nó không làm cho hiệu suất phần mềm hoặc dự án của bạn tồi tệ hơn. Việc bao gồm không gian tên ở đầu mã nguồn của bạn không phải là xấu. Việc đưa vào using namespace stdhướng dẫn thay đổi tùy theo nhu cầu của bạn và cách bạn đang phát triển phần mềm hoặc dự án.

Các namespace stdhàm chứa các biến và hàm tiêu chuẩn C ++. Không gian tên này hữu ích khi bạn thường sử dụng các hàm tiêu chuẩn C ++.

Như được đề cập trong trang này :

Câu lệnh sử dụng không gian tên std thường được coi là thực hành xấu. Thay thế cho câu lệnh này là chỉ định không gian tên mà định danh thuộc về sử dụng toán tử phạm vi (: :) mỗi lần chúng ta khai báo một kiểu.

Và xem ý kiến ​​này :

Không có vấn đề gì khi sử dụng "sử dụng không gian tên std" trong tệp nguồn của bạn khi bạn sử dụng nhiều không gian tên và biết chắc chắn rằng không có gì sẽ va chạm.

Một số người đã nói rằng việc bao gồm các using namespace stdtệp nguồn của bạn là một cách thực hành tồi vì bạn đang gọi từ không gian tên đó tất cả các hàm và biến. Khi bạn muốn xác định một hàm mới có cùng tên với một hàm khác có trong hàm, namespace stdbạn sẽ làm quá tải hàm và nó có thể tạo ra các vấn đề do biên dịch hoặc thực thi. Nó sẽ không biên dịch hoặc thực thi như bạn mong đợi.

Như được đề cập trong trang này :

Mặc dù câu lệnh lưu chúng ta khỏi việc gõ std :: bất cứ khi nào chúng ta muốn truy cập một lớp hoặc loại được xác định trong không gian tên std, nó nhập toàn bộ không gian tên std vào không gian tên hiện tại của chương trình. Chúng ta hãy lấy một vài ví dụ để hiểu tại sao điều này có thể không phải là một điều tốt như vậy

...

Bây giờ ở giai đoạn phát triển sau này, chúng tôi muốn sử dụng một phiên bản cout khác được tùy chỉnh triển khai trong một số thư viện có tên là foo foo (ví dụ)

...

Lưu ý làm thế nào có một sự mơ hồ, thư viện nào mà cout trỏ đến? Trình biên dịch có thể phát hiện điều này và không biên dịch chương trình. Trong trường hợp xấu nhất, chương trình vẫn có thể biên dịch nhưng gọi hàm sai, vì chúng tôi không bao giờ chỉ định không gian tên thuộc về định danh nào.


7

Tôi không nghĩ rằng nó thực sự là thực hành xấu trong mọi điều kiện, nhưng bạn cần cẩn thận khi sử dụng nó. Nếu bạn đang viết thư viện, có lẽ bạn nên sử dụng các toán tử phân giải phạm vi với không gian tên để giữ cho thư viện của bạn không bị húc đầu với các thư viện khác. Đối với mã cấp độ ứng dụng, tôi không thấy có gì sai với nó.


7

"Tại sao 'sử dụng không gian tên std;' được coi là một thực hành xấu trong C ++? "

Tôi nói cách khác: Tại sao một số nhân vật phụ lại bị coi là cồng kềnh?

Xem xét ví dụ viết một phần mềm số. Tại sao tôi thậm chí sẽ xem xét gây ô nhiễm không gian tên toàn cầu của mình bằng cách cắt "std :: vector" chung thành "vectơ" khi "vectơ" là một trong những khái niệm quan trọng nhất của miền vấn đề?


19
Đó không chỉ là 5 ký tự phụ; 5 ký tự thêm của nó mỗi khi bạn tham chiếu bất kỳ loại đối tượng nào trong thư viện chuẩn. Mà, nếu bạn đang sử dụng thư viện tiêu chuẩn rất nhiều, sẽ thường xuyên. Vì vậy, thực tế hơn hàng ngàn ký tự phụ trong một chương trình có kích thước khá. Có lẽ chỉ thị 'sử dụng' đã được thêm vào ngôn ngữ để có thể sử dụng nó ...
Jeremy Friesner

5
Nó không phải là 5 ký tự thêm mỗi lần, nó là 5 ký tự và có thể một vài lần nhấp chuột để kéo xuống một menu và thực hiện Tìm và Thay thế trong trình chỉnh sửa bạn chọn.
DaveWalley

1
Dễ đọc. cout << hex << setw(4) << i << endl;dễ đọc hơnstd::cout << std::hex << std::setw(4) << i << std::endl;
oz1cz

16
Và thậm chí tệ hơn: std::map<std::string,std::pair<std::string,std::string>>là khủng khiếp so với map<string,pair<string,string>>.
oz1cz

4
Đó là một thực hành tốt là dù sao cũng phải gõ các thùng chứa STL của bạn vì vậy std :: thực sự không có vấn đề gì. Và C ++ 11 mang đến cho chúng ta từ khóa tự động giúp mọi thứ trở nên dễ dàng hơn khi sử dụng các trình vòng lặp.
juzzlin

7

Tôi đồng ý với những người khác - đó là yêu cầu đụng độ tên, sự mơ hồ và sau đó thực tế là nó ít rõ ràng hơn. Trong khi tôi có thể thấy việc sử dụng using, sở thích cá nhân của tôi là hạn chế nó. Tôi cũng sẽ xem xét mạnh mẽ những gì một số người khác chỉ ra:

Nếu bạn muốn tìm một tên hàm có thể là một tên khá phổ biến, nhưng bạn chỉ muốn tìm nó trong stdkhông gian tên (hoặc ngược lại - bạn muốn thay đổi tất cả các cuộc gọi không nằm trong không gian tên std, không gian tên X, ...), Sau đó, làm thế nào để bạn đề xuất để làm điều này?

Bạn có thể viết một chương trình để thực hiện nó, nhưng sẽ tốt hơn nếu dành thời gian làm việc cho chính dự án của bạn hơn là viết một chương trình để duy trì dự án của bạn?

Cá nhân, tôi thực sự không bận tâm đến std::tiền tố. Tôi thích cái nhìn hơn là không có nó. Tôi không biết đó có phải là vì nó rõ ràng và nói với tôi "đây không phải là mã của tôi ... Tôi đang sử dụng thư viện tiêu chuẩn" hoặc nếu đó là một cái gì đó khác, nhưng tôi nghĩ nó trông đẹp hơn. Điều này có thể kỳ lạ khi tôi chỉ mới vào C ++ (đã sử dụng và vẫn sử dụng C và các ngôn ngữ khác lâu hơn nữa và C là ngôn ngữ yêu thích của tôi mọi thời đại, ngay trên phần lắp ráp).

Có một điều khác mặc dù nó có phần liên quan đến những điều trên và những gì người khác chỉ ra. Mặc dù điều này có thể là thông lệ xấu, đôi khi tôi dành std::namecho phiên bản thư viện tiêu chuẩn và tên để triển khai cụ thể theo chương trình. Vâng, thực sự điều này có thể cắn bạn và cắn bạn mạnh mẽ, nhưng tất cả là do tôi đã bắt đầu dự án này từ đầu, và tôi là lập trình viên duy nhất cho nó. Ví dụ: Tôi quá tải std::stringvà gọi nó string. Tôi có bổ sung hữu ích. Tôi đã làm điều đó một phần vì xu hướng C và Unix (+ Linux) của tôi đối với các tên viết thường.

Bên cạnh đó, bạn có thể có các bí danh không gian tên. Dưới đây là một ví dụ về nơi hữu ích mà có thể không được đề cập đến. Tôi sử dụng tiêu chuẩn C ++ 11 và đặc biệt với libstdc ++. Vâng, nó không có std::regexhỗ trợ đầy đủ . Chắc chắn, nó biên dịch, nhưng nó ném một ngoại lệ dọc theo dòng của nó là một lỗi ở phần cuối của lập trình viên. Nhưng nó thiếu thực hiện.

Vì vậy, đây là cách tôi giải quyết nó. Cài đặt regex của Boost và liên kết nó. Sau đó, tôi làm như sau để khi libstdc ++ thực hiện hoàn toàn, tôi chỉ cần xóa khối này và mã vẫn giữ nguyên:

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

Tôi sẽ không tranh luận về việc đó có phải là một ý tưởng tồi hay không. Tuy nhiên, tôi sẽ lập luận rằng nó giữ sạch cho dự án của tôi và đồng thời làm cho nó cụ thể: Đúng, tôi phải sử dụng Boost, nhưng tôi đang sử dụng nó như libstdc ++ cuối cùng sẽ có nó. Có, bắt đầu dự án của riêng bạn và bắt đầu với một tiêu chuẩn (...) ngay từ đầu đã đi một chặng đường rất dài với việc giúp bảo trì, phát triển và mọi thứ liên quan đến dự án!

Chỉ cần làm rõ điều gì đó: Tôi thực sự không nghĩ rằng nên sử dụng tên của một lớp / bất cứ điều gì trong STL một cách có chủ ý và cụ thể hơn thay cho. Chuỗi là ngoại lệ (bỏ qua lần đầu tiên, ở trên hoặc thứ hai ở đây, chơi chữ nếu bạn phải) đối với tôi vì tôi không thích ý tưởng về 'Chuỗi'.

Như vậy, tôi vẫn rất thiên về C và thiên vị so với C ++. Chi tiết tiết kiệm, phần lớn những gì tôi làm việc phù hợp với C nhiều hơn (nhưng đó là một bài tập tốt và là cách tốt để khiến bản thân tôi học một ngôn ngữ khác và b. Cố gắng không bị thiên vị so với đối tượng / lớp / v.v. như ít khép kín, ít kiêu ngạo và chấp nhận nhiều hơn.). Nhưng những gì hữu ích là những gì một số đã đề nghị: Tôi thực sự sử dụng danh sách (đó là khá chung chung, là nó không?), Và sắp xếp (điều tương tự) để đặt tên hai có thể gây ra một cuộc đụng độ tên nếu tôi được làm using namespace std;, và do đó Cuối cùng, tôi thích cụ thể hơn, kiểm soát và biết rằng nếu tôi dự định đó là sử dụng tiêu chuẩn thì tôi sẽ phải chỉ định nó. Nói một cách đơn giản: không cho phép giả định.

Và như để làm phần regex của Boost std. Tôi làm điều đó để hội nhập trong tương lai và - một lần nữa, tôi thừa nhận hoàn toàn đây là sự thiên vị - tôi không nghĩ nó xấu như vậy boost::regex:: .... Thật vậy, đó là một điều khác cho tôi. Có nhiều điều trong C ++ mà tôi vẫn chưa chấp nhận hoàn toàn về ngoại hình và phương thức (một ví dụ khác: các mẫu matrixdic so với var argument [mặc dù tôi thừa nhận các mẫu matrixdic rất rất hữu ích!]). Ngay cả những điều mà tôi chấp nhận nó cũng khó khăn tôi vẫn có vấn đề với họ.


1
Mở rộng stdkhông gian tên là hành vi không xác định và do đó không bao giờ nên được thực hiện.
tambre

7

Từ kinh nghiệm của tôi, nếu bạn có nhiều thư viện sử dụng nói cout, nhưng với mục đích khác, bạn có thể sử dụng sai cout.

Ví dụ, nếu tôi gõ vào, using namespace std;using namespace otherlib;và gõ chỉ cout(mà sẽ xảy ra là trong cả hai), chứ không phải std::cout(hoặc 'otherlib::cout'), bạn có thể sử dụng một trong những sai lầm, và nhận lỗi. Nó hiệu quả và hiệu quả hơn nhiều để sử dụng std::cout.


6

Với các định danh nhập không đủ tiêu chuẩn, bạn cần các công cụ tìm kiếm bên ngoài như grep để tìm ra nơi định danh được khai báo. Điều này làm cho lý luận về tính chính xác của chương trình khó hơn.


6

Nó phụ thuộc vào vị trí của nó. Nếu nó là một tiêu đề phổ biến, thì bạn đang làm giảm giá trị của không gian tên bằng cách hợp nhất nó vào không gian tên toàn cầu. Hãy nhớ rằng, đây có thể là một cách gọn gàng để tạo mô-đun toàn cầu.


6

Đây là một thực tiễn xấu, thường được gọi là ô nhiễm không gian tên toàn cầu. Sự cố có thể xảy ra khi có nhiều hơn một không gian tên có cùng tên hàm với chữ ký, do đó trình biên dịch sẽ không rõ ràng để quyết định nên gọi cái nào và tất cả có thể tránh được khi bạn chỉ định không gian tên với hàm gọi của bạn std::cout. Hi vọng điêu nay co ich. :)


5

Để trả lời câu hỏi của bạn, tôi nhìn vào nó theo cách này một cách thực tế: rất nhiều lập trình viên (không phải tất cả) gọi không gian tên std. Do đó, người ta nên có thói quen KHÔNG sử dụng những thứ bắt chước hoặc sử dụng cùng tên với những gì trong không gian tên std. Đó là một thỏa thuận tuyệt vời được cấp, nhưng không quá nhiều so với số lượng các từ và bút danh mạch lạc có thể được đưa ra với cách nói nghiêm túc.

Ý tôi là thực sự ... nói rằng "đừng dựa vào sự hiện diện này" chỉ là thiết lập cho bạn dựa vào nó KHÔNG hiện diện. Bạn liên tục gặp vấn đề khi mượn đoạn mã và liên tục sửa chữa chúng. Chỉ cần giữ các công cụ do người dùng xác định và mượn trong phạm vi hạn chế như họ nên và RẤT không phụ thuộc vào toàn cầu (trung thực toàn cầu nên luôn luôn là phương sách cuối cùng cho mục đích "biên dịch ngay bây giờ, tỉnh táo sau"). Thực sự tôi nghĩ rằng đó là lời khuyên tồi từ giáo viên của bạn bởi vì sử dụng std sẽ hoạt động cho cả "cout" và "std :: cout" nhưng KHÔNG sử dụng std sẽ chỉ hoạt động cho "std :: cout". Bạn sẽ không đủ may mắn để viết tất cả mã của riêng bạn.

LƯU Ý: Đừng tập trung quá nhiều vào các vấn đề hiệu quả cho đến khi bạn thực sự tìm hiểu một chút về cách trình biên dịch làm việc. Với một chút kinh nghiệm mã hóa, bạn không cần phải tìm hiểu nhiều về chúng trước khi bạn nhận ra họ có thể khái quát hóa mã tốt thành một thứ gì đó đơn giản đến mức nào. Mỗi bit đơn giản như thể bạn đã viết toàn bộ trong C. Mã tốt chỉ phức tạp như nó cần phải có.


Dựa vào việc có bao nhiêu người dân dường như không biết về các chức năng thư viện tiêu chuẩn hữu ích ( <algorithm>ví dụ như phát minh lại mọi thứ từ đó ), có vẻ hơi khó để tưởng tượng rằng cùng một người có thể tránh những định danh đó một cách đáng tin cậy. Xem qua mã của riêng bạn và cho tôi biết bạn không bao giờ có một biến hoặc hàm được gọi count. Hoặc distance, hay log, destroy, launch, visit, beta, sample, messages, clamp, erase, copy, modulus, left,, vv Chưa kể tất cả các định danh chưa có trong stdđó sẽ phá vỡ mã của bạn khi C ++ 35 đi ra ...
Toby Speight
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.