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

Sep 21 2009

Tôi đã nói với người khác rằng văn bản using namespace std;trong mã là sai, và rằng tôi nên sử dụng std::coutstd::cintrực tiếp để thay thế.

Tại sao được using namespace std;coi là một thực hành xấu? Nó không hiệu quả hay nó có nguy cơ khai báo các biến không rõ ràng (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 không?

Trả lời

2351 GregHewgill Sep 21 2009 at 10:13

Điều này hoàn toàn 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 là Foo và Bar:

using namespace foo;
using namespace bar;

Mọi thứ 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 bạn nâng cấp lên phiên bản Foo 2.0 mới, hiện cung cấp một chức năng được gọi là Quux(). Bây giờ bạn có xung đột: Cả Foo 2.0 và Bar đều nhập Quux()vào không gian tên chung của bạn. Điều này sẽ mất một số nỗ lực để khắc phục, đặc biệt nếu các tham số hàm trùng khớp.

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

1442 sbi Sep 21 2009 at 16:26

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 những gì 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 chức năng rõ ràng tốt hơn cho một số lệnh gọi của bạn Quux()so với bar::Quux()mã của bạn đã 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 sai chức năng và không biết điều. Đó là đ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 là không chắc: Có một câu hỏi được hỏi ở đây trên Stack Overflow nơi mà chính xác là điều này đã xảy ra khá nhiều (gọi sai hàm 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 về 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 phiền phức khi phải thêm tiền tố mọi thứ từ thư viện tiêu chuẩn với std::. Sau đó, tôi đã làm việc trong một dự án mà ngay từ đầu nó đã được quyết định rằng cả usingchỉ thị và khai báo đều bị cấm ngoại trừ phạm vi chức năng. Đoán xem nào? 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 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ố một cách khách quan bổ sung sự rõ ràng cho mã. Không chỉ trình biên dịch mà bạn cũng thấy dễ dàng hơn khi xem mã định danh nào được tham chiếu.

Trong một thập kỷ, dự án đó đã tăng lên đến vài triệu dòng mã. Kể từ khi các cuộc thảo luận này lặp đi lặp lại, tôi đã từng tò mò tần suất phạm vi chức năng (được phép) usingthực sự được sử dụng trong dự án. Tôi đã tìm kiếm các nguồn cho nó và chỉ tìm thấy một hoặc hai chục nơi mà nó đượ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::đủ khó khăn để sử dụng các chỉ thị ngay cả khi cứ 100 kLoC một lần ngay cả khi nó được phép sử dụng.


Điểm mấu chốt: Việc đặt tiền tố rõ ràng cho 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 biệt, nó làm cho mã dễ hiểu hơn bởi trình biên dịch và người đọc của con người - và đó có lẽ phải là mục tiêu chính khi viết mã.

453 ChrisW Sep 21 2009 at 10:22

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 khác đó.

Tuy nhiên, bạn có thể thoải mái đặt câu lệnh using vào các tệp * .cpp (riêng tư) của mình.


Hãy lưu ý rằng một số người không đồng ý với câu nói của tôi "hãy thoải mái" như thế này - bởi vì mặc dù một usingcâu lệnh 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), 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 triển khai lớp khó duy trì hơn). Mục nhập C ++ Super-FAQ này cho biết,

Chỉ thị using tồn tại cho mã C ++ kế thừa và để dễ dàng chuyển đổi sang không gian tên, nhưng bạn có thể không nên sử dụng nó 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 đề xuất 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:";
    
241 DavidThornley Oct 29 2010 at 00:37

Gần đây tôi đã gặp phải khiếu nại về Visual Studio 2010 . Hóa ra hầu hết tất cả các tệp nguồn đều có hai dòng sau:

using namespace std;
using namespace boost;

Rất nhiều tính năng Boost được đưa 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 kiểm tra trong tương lai, một cách để đảm bảo rằng một thay đổi đối với các thư viện và / hoặc tệp tiêu đề đang được sử dụng sẽ không phá vỡ một chương trình.

216 mattnewport Nov 04 2014 at 03:00

Phiên bản ngắn: không sử dụng usingkhai báo hoặc chỉ thị toàn cục trong tệp tiêu đề. Hãy thoải mái sử dụng chúng trong các tệp triển khai. Đây là những gì Herb Sutter và Andrei Alexandrescu phải nói về vấn đề này trong Tiêu chuẩn mã hóa C ++ (viết tắt để 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 hại cho người khác: Không bao giờ viết khai báo using hoặc chỉ thị using trước chỉ thị #include.

Hệ quả: Trong tệp tiêu đề, không viết cấp không gian tên bằng cách sử dụng lệnh hoặc sử dụng khai báo; thay vào đó, không gian tên rõ ràng đủ điều kiện cho tất cả các tên. (Quy tắc thứ hai tuân theo quy tắc đầu tiên, vì các tiêu đề không bao giờ có thể biết được tiêu đề nào khác #includes 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à lệnh một cách tự do trong các tệp triển khai của mình sau các lệnh #include và cảm thấy hài lòng về nó. Mặc dù nhiều lần khẳng định ngược lại, không gian tên sử dụng các khai báo và chỉ thị không phải là xấu và chúng không đánh bại mục đích của không gian tên. Đúng hơn, chúng là thứ làm cho không gian tên có thể sử dụng được .

128 robson3.14 Sep 21 2009 at 22:47

Người ta không nên sử dụng usingchỉ thị ở phạm vi toàn cục, đặc biệt là trong các tiêu đề. Tuy nhiên, có những trường hợp nó 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 chứng chỉ 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 kiểu 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)).

100 towi Jan 18 2013 at 16:34

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 mà bạn đang lập trình.
  • Người đọc sẽ gặp khó khăn khi thấy một số nhận dạng cụ thể đến từ đâu, khi bạn sử dụng nhiều using namespace xyz.
  • Bất cứ điều gì đúng đối với những người đọc khác của 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: chính bạn. Hãy quay lại sau một hoặc hai năm và xem lại ...
  • Nếu bạn chỉ nói về using namespace stdbạn, bạn có thể không biết tất cả những thứ bạn lấy - và khi bạn thêm một thứ khác #includehoặc chuyển sang bản sửa đổi C ++ mới, bạn có thể nhận được xung đột tên mà bạn không biết.

Bạn có thể sử dụng nó tại địa phương

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

Một thành ngữ để sử dụng nó tại địa phương

Trong C ++ 03 có một thành ngữ - mã viết sẵn - để triển khai một swaphàm cho các lớp của bạn. Chúng tôi đề xuất rằng bạn thực sự sử dụng cục bộ 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 điều kỳ diệu 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 void swap(Child&, Child&)thực hiện quá tải , trình biên dịch sẽ chọn nó.
  • Nếu bạn không gặp phải tình trạng quá tải đó, trình biên dịch sẽ sử dụng void std::swap(Child&,Child&)và cố gắng hoán đổi tốt nhất những thứ này.

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 ra một sự quá tải tiềm ẩn và chọn nó.

81 sth Sep 21 2009 at 10:23

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 cái 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ả nội dung 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ề sự xung đột tên với mã của bạn hoặc các thư viện khác.

52 MartinBeckett Sep 21 2009 at 10:13

Một lý do khác là sự ngạc nhiên.

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

49 AlexanderPoluektov Mar 29 2011 at 15:10

Các lập trình viên có kinh nghiệm sử dụng bất kỳ thứ gì giải quyết được vấn đề của họ và tránh bất kỳ thứ gì tạo ra vấn đề mới và họ tránh sử dụng các chỉ thị cấp tiêu đề-tệp 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 việc xác định đầy đủ các tên bên trong tệp nguồn của họ. Một lý do nhỏ cho điều này là không nên viết nhiều mã hơn khi ít mã hơn là đủ trừ khi có lý do chính đáng . Một lý do chính cho điều này là tắt tra cứu phụ thuộc vào đối số (ADL).

Những lý do chính đáng này là gì? Đôi khi các lập trình viên muốn tắt ADL một cách rõ ràng, những lần khác họ muốn phân biệt.

Vì vậy, những điều sau đây là OK:

  1. Các chỉ thị sử dụng cấp hàm và các khai báo sử dụng bên trong việc triển khai các hàm
  2. Nguồn-tệp-cấp sử dụng-khai báo bên trong tệp nguồn
  3. (Đôi khi) sử dụng chỉ thị cấp nguồn-tệp
46 Oleksiy Aug 29 2013 at 16:44

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 và sự không rõ ràng 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 các khai báo như His_lib::String) sẽ được ưu tiên hơn các tên có thể truy cập được trong phạm vi khác bằng chỉ thị using ( using namespace Her_lib).

32 Yelonek Sep 21 2009 at 16:34

Tôi cũng coi đó là một tập tục tồi tệ. Tại sao? Chỉ một ngày nọ, tôi nghĩ rằng chức năng của một không gian tên là phân chia mọi thứ, 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 chung.

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 đề khi nó truyền với #include). Tôi nghĩ rằng không ai lành mạnh sẽ bao giờ đặt tên cho một dòng suối couthoặc cin. ;)

27 gnasher729 Mar 14 2014 at 00:22

Thật tuyệt khi xem mã và biết nó làm gì. Nếu tôi thấy, std::couttôi biết đó là coutluồng của stdthư viện. Nếu tôi thấy coutthì tôi không biết. Nó có thểcoutluồ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 đó. Nó có thể là bất cứ điều gì.

Bây giờ hãy lấy một triệu dòng mã cơ sở, không phải là đặc biệt lớn và bạn đang tìm kiếm một lỗi, có nghĩa là bạn biết rằng 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 static inttên cout, dịch chuyển nó sang trái một chút và loại bỏ kết quả. Tìm kiếm một lỗi, tôi phải kiểm tra nó. Bạn có thể thấy tôi thực sự thích xem std::coutnhư thế nào không?

Đó là một trong những điều này có vẻ là một ý tưởng thực sự tốt nếu bạn là một giáo viên và chưa 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ã trong đó (1) Tôi biết nó làm gì; và, (2) Tôi tin rằng người viết nó biết nó làm gì.

25 PreetSangha Sep 21 2009 at 10:14

Đó là tất cả về quản lý sự phức tạp. Sử dụng không gian tên sẽ kéo những 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 theo cách bạn có thể và cảm thấy tốt nhất có thể.

20 RonWarholic Sep 21 2009 at 10:19

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à các lần nhập khác, bạn sẽ có rất nhiều phụ thuộc phải trải qua để 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.

Nó không quá kinh khủng, nhưng bạn sẽ đỡ phả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 chung. Có lẽ không sao khi 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 nhập năm ký tự bổ sung để làm rõ các chức năng của tôi đến từ đâu.

19 Kevin Sep 03 2016 at 03:06

Một ví dụ cụ thể để làm rõ mối lo ngại. 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ờ giả sử 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, nó "Có gì đó". Nhưng sau đó bạn cập nhật barvà giả sử nó đã thay đổi thành như sau:

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 phải thực hiện một số bảo trì để làm rõ nghĩa của 'a' foo::a. Đó là điều không mong muốn, nhưng may mắn thay, nó khá dễ dàng (chỉ cần thêm foo::vào trước tất cả các lệnh gọi amà trình biên dịch đánh dấu là mơ hồ).

Nhưng hãy tưởng tượng một tình huống thay thế trong đó thanh thay đổi thành như thế này thay thế:

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

Tại thời điểm này, lời kêu gọi của bạn a(42)đột nhiên liên kết với bar::athay vì foo::avà thay vì làm 'điều gì đó', nó thực hiện 'điều 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 chỉnh khác với trước đây.

Khi bạn sử dụng một không gian tên, bạn đang gặp rủi ro trong một tình huống như thế này, đó là lý do tại sao mọi người không thoải mái khi sử dụng 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, vì vậy mọi người có thể thậm chí còn khó chịu hơn khi sử dụng không gian tên std(do số lượng thứ trong không gian tên đó) so với các không gian tên khác.

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

18 user2645752 Nov 09 2013 at 22:09

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 dẫn đến thảm họa, nhưng sử dụng không gian tên JUST stdvà không gian tên duy nhất không stdphải là vấn đề lớn theo quan điểm của tôi vì việc xác định lại chỉ có thể xảy ra bằng mã của riêng bạn ...

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

Mọi người nên đừng quá lo lắng về nó. Giáo viên của bạn đã đúng tất cả. 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 ngay từ đầu. Bạn không được phép sử dụng nhiều hơn một cái 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, việc xác định lại sẽ không xảy ra.

18 DustinGetz Sep 21 2009 at 11:04
  1. Bạn cần có khả năng đọc mã được viết bởi những người có phong cách và ý kiến ​​về phương pháp hay nhất khác 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ó 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ó hoạt động như thế nào, thì việc không gian tên rõ ràng đóng vai trò như một nhận xét. Thoạt nhìn, bạn có thể thấy "ồ, đây là hoạt động của hệ thống tệp" hoặc "đang thực hiện công cụ mạng".

14 Carl Feb 12 2015 at 07:40

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

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à 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 quá trình 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;
}
14 RohanSingh Apr 05 2015 at 19:56

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à để giữ các mục riêng biệt tách 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 để tham chiếu đến 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
    // ...
}

Việc lặp lại tên không gian tên có thể gây mất tập trung cho cả người đọc và người viết. Do đó, có thể tuyên bố rằng các tên từ một không gian tên cụ thể có sẵn mà không cần trình độ 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 biệt, họ cung cấp cho lập trình viên các lựa chọn thay thế về cách rõ ràng để tạo tham chiếu đến tên phi địa phương.

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

11 Nithin Dec 31 2014 at 15:00

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

#include <iostream>
#include <algorithm>

using namespace std;

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

Nó không làm cho hiệu suất phần mềm hoặc dự án của bạn kém đi. 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 bao gồm 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.

Hàm namespace stdchứa các hàm và biến 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à hành vi xấu. Giải pháp thay thế cho câu lệnh này là chỉ định không gian tên mà mã định danh thuộc về bằng cách sử dụng toán tử phạm vi (: :) mỗi khi 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 "using namespace 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 rằng sẽ không có gì xung đột.

Một số người đã nói rằng đó là một phương pháp không tốt khi đưa using namespace stdtệp nguồn của bạn vào 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 giúp chúng ta không phải nhập std :: bất cứ khi nào chúng ta muốn truy cập vào một lớp hoặc kiểu được xác định trong không gian tên std, nó sẽ 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. Hãy để chúng tôi 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, chúng tôi muốn sử dụng một phiên bản cout khác được triển khai tùy chỉnh trong một số thư viện có tên là “foo” (ví dụ)

...

Lưu ý rằng có một sự mơ hồ, cout trỏ đến thư viện nào? 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 sai hàm, vì chúng tôi chưa bao giờ chỉ định không gian tên nào mà mã định danh thuộc về.

8 Dr.Watson Sep 21 2009 at 10:34

Tôi không nghĩ rằng nó nhất thiết phải thực hành xấu trong mọi điều kiện, nhưng bạn cần phải cẩn thận khi sử dụng nó. Nếu bạn đang viết mộ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ị tấn công bở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ó.

8 Noname Oct 14 2014 at 00:30

Tôi đồng ý với những người khác - đó là yêu cầu xung đột tên, sự không rõ ràng và sau đó thực tế là nó ít rõ ràng hơn. Mặc dù tôi có thể thấy việc sử dụng using, nhưng sở thích cá nhân của tôi là hạn chế nó. Tôi cũng rất muốn xem xét 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 lệnh gọi không có trong không gian tên std, không gian tên X, ...), sau đó bạn đề xuất làm điều này như thế nào?

Bạn có thể viết một chương trình để làm điều đó, 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" hay nếu nó 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ể là kỳ lạ khi tôi chỉ mới làm quen với C ++ (đã sử dụng và vẫn sử dụng C và các ngôn ngữ khác trong thời gian dài hơn nữa và C là ngôn ngữ yêu thích của tôi mọi lúc, ngay trên assembly).

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à một phương pháp không tốt, nhưng đôi khi tôi đặt trước std::namecho phiên bản thư viện tiêu chuẩn và tên để triển khai chương trình cụ thể. Vâng, thực sự điều này có thể cắn bạn và cắn bạn rất mạnh, nhưng tất cả bắt nguồn từ việc 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ó những 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ó bí danh không gian tên. Đây là một ví dụ về nơi nó hữu ích mà có thể chưa được đề cập đến. Tôi sử dụng tiêu chuẩn C ++ 11 và cụ thể là với libstdc ++. Chà, nó không có std::regexhỗ trợ đầy đủ . Chắc chắn, nó biên dịch, nhưng nó ném ra một ngoại lệ dọc theo dòng của nó là một lỗi ở phía lập trình viên. Nhưng nó là 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ó vào. Sau đó, tôi làm như sau để khi libstdc ++ đã được triển khai hoàn toàn, tôi chỉ cần xóa khối này và mã vẫn như cũ:

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ữ cho nó sạch sẽ 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ó. Vâng, việ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 sẽ giúp bạn duy trì, phát triển và mọi thứ liên quan đến dự án một chặng đường rất dài!

Chỉ để làm rõ điều gì đó: Tôi thực sự không nghĩ rằng việc sử dụng tên của một lớp / bất cứ thứ gì trong STL một cách có chủ ý và cụ thể hơn là một ý tưởng hay . Chuỗi là ngoại lệ (bỏ qua đầ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'.

Vì hiện tại, tôi vẫn rất thành kiến ​​với C và thiên vị đối với C ++. Tiết kiệm chi tiết, phần lớn những gì tôi làm việc phù hợp với C hơn (nhưng đó là một bài tập tốt và là một cách tốt để khiến bản thân trở thành một. Học một ngôn ngữ khác và b. Cố gắng không thành kiến ​​ít hơn đối với đối tượng / các lớp / v.v. có lẽ tốt hơn như ít khép kín hơn, ít kiêu ngạo hơn và chấp nhận 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 đó vì mục đích đó, tôi thích cụ thể, có kiểm soát và biết rằng nếu tôi muốn nó trở thành mục đích 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à đối với việc biến regex của Boost trở thành một phần của std. Tôi làm điều đó để hội nhập trong tương lai và - một lần nữa, tôi hoàn toàn thừa nhậ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 đối với tôi. Có nhiều thứ 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: mẫu variadic so với đối số var [mặc dù tôi thừa nhận các mẫu variadic rất hữu ích!]). Ngay cả những người mà tôi chấp nhận nó cũng khó, tôi vẫn có vấn đề với chúng.

8 EngineDev Aug 21 2016 at 05:55

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

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

8 SwissFrank May 23 2019 at 05:05

Đó là từng trường hợp. Chúng tôi muốn giảm thiểu "tổng chi phí sở hữu" phần mềm trong suốt thời gian tồn tại của nó. Nói "sử dụng không gian tên std" có một số chi phí, nhưng không sử dụng nó cũng có chi phí trong tính dễ đọc.

Mọi người chỉ ra một cách chính xác rằng khi sử dụng nó, khi thư viện chuẩn giới thiệu các ký hiệu và định nghĩa mới, mã của bạn sẽ ngừng biên dịch và bạn có thể bị buộc phải đổi tên các biến. Tuy nhiên, điều này có lẽ là tốt về lâu dài, vì những người bảo trì trong tương lai sẽ bị nhầm lẫn hoặc mất tập trung trong giây lát nếu bạn đang sử dụng một từ khóa cho một mục đích đáng ngạc nhiên nào đó.

Bạn không muốn có một mẫu được gọi là vectơ, chẳng hạn như vectơ mà những người khác không biết. Và số lượng các định nghĩa mới do đó được giới thiệu trong thư viện C ++ là đủ ít nên nó có thể đơn giản là không xuất hiện. Có một chi phí có liên quan tới kiểu thay đổi này, nhưng chi phí không cao và được bù đắp bởi sự rõ ràng đã đạt được bằng cách không sử dụng stdtên biểu tượng cho các mục đích khác.

Với số lượng các lớp, biến và hàm, việc nêu rõ std::trên mỗi lớp có thể làm rối mã của bạn lên 50% và khiến bạn khó tìm hiểu hơn. Một thuật toán hoặc bước trong một phương pháp có thể được thực hiện trên một đoạn mã màn hình hiện yêu cầu cuộn qua lại để làm theo. Đây là một chi phí thực tế. Có thể cho rằng nó có thể không phải là một chi phí cao, nhưng những người phủ nhận nó thậm chí còn tồn tại là những người thiếu kinh nghiệm, giáo điều, hoặc đơn giản là sai lầm.

Tôi sẽ đưa ra các quy tắc sau:

  1. stdkhác với tất cả các thư viện khác. Đó là một thư viện mà mọi người về cơ bản cần biết, và theo quan điểm của tôi, tốt nhất nên coi đây là một phần của ngôn ngữ. Nói chung, có một trường hợp tuyệt vời cho using namespace stdngay cả khi không có cho các thư viện khác.

  2. Không bao giờ ép buộc tác giả của một đơn vị biên dịch (tệp .cpp) đưa ra quyết định bằng cách đặt điều này usingvào tiêu đề. Luôn trì hoãn quyết định cho tác giả đơn vị biên soạn. Ngay cả trong một dự án đã quyết định sử dụng using namespace stdở mọi nơi có thể phạt một số mô-đun được xử lý tốt nhất như là ngoại lệ cho quy tắc đó.

  3. Mặc dù tính năng không gian tên cho phép bạn có nhiều mô-đun với các ký hiệu được định nghĩa giống nhau, nhưng sẽ rất khó hiểu khi làm như vậy. Giữ các tên khác nhau trong phạm vi có thể. Ngay cả khi không sử dụng tính năng không gian tên, nếu bạn có một lớp được đặt tên foostdgiới thiệu một lớp được đặt tên foo, có lẽ tốt hơn là bạn nên đổi tên lớp của mình về lâu dài.

  4. Một cách thay thế cho việc sử dụng không gian tên là ký hiệu không gian tên theo cách thủ công bằng cách thêm tiền tố vào chúng. Tôi có hai thư viện mà tôi đã sử dụng trong nhiều thập kỷ, cả hai đều bắt đầu là thư viện C, trên thực tế, mọi ký hiệu đều có tiền tố là "AK" hoặc "SCWin". Nói chung, điều này giống như tránh cấu trúc "using", nhưng bạn không viết dấu hai chấm. AK::foo()là thay vào đó AKFoo(). Nó làm cho mã dày hơn 5-10% và ít dài dòng hơn, và nhược điểm duy nhất là bạn sẽ gặp rắc rối lớn nếu phải sử dụng hai thư viện có tiền tố giống nhau. Lưu ý rằng các thư viện X Window rất tuyệt vời về mặt này, ngoại trừ việc chúng quên làm như vậy với một số #defines: TRUE và FALSE lẽ ra phải là XTRUE và XFALSE, và điều này thiết lập xung đột không gian tên với Sybase hoặc Oracle cũng sử dụng TRUE và FALSE với các giá trị khác nhau! (ASCII 0 và 1 trong trường hợp cơ sở dữ liệu!) Một ưu điểm đặc biệt của điều này là nó dường như không áp dụng cho các định nghĩa tiền xử lý, trong khi C ++ using/ namespacesystem không xử lý chúng. Một lợi ích tuyệt vời của điều này là nó tạo ra một độ dốc hữu cơ từ việc trở thành một phần của dự án để cuối cùng trở thành một thư viện. Trong một ứng dụng lớn của tôi, tất cả các lớp cửa sổ đều có tiền tố Win, tất cả các mô-đun xử lý tín hiệu là Mod, v.v. Có rất ít cơ hội để bất kỳ thứ nào trong số này được sử dụng lại, vì vậy sẽ không có lợi ích thiết thực nào khi đưa mỗi nhóm thành một thư viện, nhưng sẽ rõ ràng trong vài giây về cách dự án chia thành các dự án con.

7 AugustKarlstrom Apr 11 2013 at 21:22

Với các số nhận dạng được 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 các số nhận dạng được khai báo. Điều này làm cho việc lập luận về tính đúng đắn của chương trình khó hơn.

7 MathGladiator Sep 21 2009 at 10:15

Nó phụ thuộc vào vị trí của nó. Nếu nó là một tiêu đề chung, thì bạn đang 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 chung. Hãy nhớ rằng, đây có thể là một cách đơn giản để tạo ra hình cầu mô-đun.

7 adn.911 Nov 30 2017 at 23:24

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

6 NoneyoGetit Jun 28 2013 at 03:33

Để trả lời câu hỏi của bạn, tôi xem xét nó theo cách thực tế: rất nhiều lập trình viên (không phải tất cả) gọi std không gian tên. Vì vậy, người ta nên có thói quen KHÔNG sử dụng những thứ cản trở hoặc sử dụng các tên giống với những gì có trong std không gian tên. Đó là một con số rất lớn, 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ó khi nói một cách chính xác.

Ý tôi là thực sự ... nói "đừng dựa vào sự hiện hữu này" chỉ là bạn đang thiết lập để dựa vào nó KHÔNG hiện diện. Bạn liên tục gặp sự cố khi mượn đoạn mã và liên tục sửa chữa chúng. Chỉ cần giữ nội dung do người dùng xác định và cho mượn của bạn trong phạm vi giới hạn như chúng nên có và RẤT tiết kiệm với toàn cầu (thành thật mà nói, toàn cầu hầu như 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ĩ đó là lời khuyên tồi từ giáo viên của bạn 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". Không phải lúc nào bạn cũng đủ may mắn để viết tất cả mã của riêng mình.

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