2011-05-01 36 views
99

Trong tất cả các khóa học C++ của chúng tôi, tất cả giáo viên luôn đặt using namespace std; ngay sau #include s trong các tệp .h của chúng. Điều này dường như với tôi là nguy hiểm kể từ đó bằng cách đưa tiêu đề đó vào chương trình khác, tôi sẽ nhận được không gian tên được nhập vào chương trình của tôi, có thể không nhận ra, dự định hoặc muốn nó (bao gồm tiêu đề có thể lồng nhau rất sâu)."sử dụng không gian tên" trong tiêu đề C++

Vì vậy, câu hỏi của tôi là kép: Tôi có quyền đó using namespace nên không được sử dụng trong các tập tin tiêu đề, và/hoặc là có một số cách để hủy bỏ nó, một cái gì đó như:

//header.h 
using namespace std { 
. 
. 
. 
} 

Một câu hỏi nữa dọc theo cùng dòng: Tập tin tiêu đề có phải là #include tất cả tiêu đề tương ứng với .cpp nhu cầu tệp hay không, chỉ cho phép các tệp .cpp#include phần còn lại hoặc không và khai báo mọi thứ cần là extern?
Lý do đằng sau câu hỏi là giống như trên: Tôi không muốn bất ngờ khi bao gồm các tệp .h.

Ngoài ra, nếu tôi đúng, đây có phải là lỗi thường gặp không? Ý tôi là trong lập trình thế giới thực và trong các dự án "thực" ngoài kia.

Cảm ơn bạn.

+3

http://stackoverflow.com/questions/1265039/using-std-namespace –

+2

là một lưu ý phụ, nếu bạn nhận được các xung đột tên do các câu lệnh 'using namespace' thì bạn có thể sử dụng tên đầy đủ để giải quyết vấn đề. –

Trả lời

87

Bạn chắc chắn KHÔNG nên sử dụng using namespace trong tiêu đề chính xác vì lý do bạn nói, có thể bất ngờ thay đổi ý nghĩa của mã trong bất kỳ tệp nào khác bao gồm tiêu đề đó. Không có cách nào để hoàn tác using namespace đó là một lý do khác khiến nó nguy hiểm đến vậy. Tôi thường chỉ sử dụng grep hoặc tương tự để đảm bảo rằng using namespace không được gọi ra trong tiêu đề thay vì thử bất cứ điều gì phức tạp hơn. Có lẽ mã kiểm tra tĩnh cờ này quá.

Tiêu đề chỉ nên bao gồm tiêu đề cần phải biên dịch. Một cách dễ dàng để thực thi điều này là luôn bao gồm tiêu đề của từng tệp nguồn làm đầu tiên, trước bất kỳ tiêu đề nào khác. Sau đó, các tập tin nguồn sẽ không biên dịch nếu tiêu đề không phải là khép kín. Trong một số trường hợp, ví dụ như tham chiếu đến các lớp chi tiết thực hiện trong một thư viện, bạn có thể sử dụng các khai báo chuyển tiếp thay vì #include vì bạn có toàn quyền kiểm soát định nghĩa của lớp được khai báo chuyển tiếp đó.

Tôi không chắc chắn tôi sẽ gọi nó là phổ biến, nhưng nó chắc chắn xuất hiện một lần trong một thời gian, thường được viết bởi các lập trình mới mà không nhận thức được những hậu quả tiêu cực. Thông thường chỉ là một chút giáo dục về những rủi ro sẽ chăm sóc bất kỳ vấn đề nào vì nó tương đối đơn giản để sửa chữa.

4

Bạn nói đúng. Và bất kỳ tệp nào cũng chỉ bao gồm các tiêu đề cần thiết bởi tệp đó. Đối với "đang làm những điều sai lầm phổ biến trong các dự án thế giới thực?" - ồ, vâng!

5

Bạn đúng rằng using namespace trong tiêu đề là nguy hiểm. Tôi không biết cách hoàn tác. Thật dễ dàng để phát hiện nó, tuy nhiên chỉ cần tìm kiếm using namespace trong các tệp tiêu đề. Vì lý do cuối cùng nó không phổ biến trong các dự án thực tế. Nhiều đồng nghiệp có kinh nghiệm hơn sẽ sớm phàn nàn nếu ai đó làm điều gì đó giống như vậy.

Trong các dự án thực tế, mọi người cố gắng giảm thiểu số lượng tệp được bao gồm, bởi vì bạn càng tính toán nhanh hơn. Điều đó tiết kiệm thời gian của mọi người. Tuy nhiên, nếu tập tin tiêu đề giả định rằng một cái gì đó nên được bao gồm trước khi nó sau đó nó nên bao gồm nó chính nó. Nếu không, nó sẽ làm cho tiêu đề không bị khép kín.

12

Bạn cần phải cẩn thận khi bao gồm tiêu đề bên trong tiêu đề. Trong các dự án lớn, nó có thể tạo ra một chuỗi phụ thuộc rất rối khiến cho việc xây dựng lại lớn hơn/dài hơn thực sự cần thiết. Hãy xem this articleits follow-up để tìm hiểu thêm về tầm quan trọng của cấu trúc vật lý tốt trong các dự án C++.

Bạn chỉ nên bao gồm tiêu đề bên trong tiêu đề khi cần thiết (bất cứ khi nào định nghĩa đầy đủ của lớp) và sử dụng khai báo ở bất cứ nơi nào bạn có thể (khi lớp được yêu cầu là con trỏ hoặc tham chiếu).

Đối với không gian tên, tôi có xu hướng sử dụng phạm vi không gian tên rõ ràng trong tệp tiêu đề của tôi và chỉ đặt using namespace trong tệp cpp của tôi.

+2

+1 để nhấn mạnh các khai báo chuyển tiếp bất cứ khi nào có thể. –

3

Giống như tất cả mọi thứ trong lập trình, chủ nghĩa thực dụng nên giành chiến thắng trên thuyết giáo lý, IMO.

Miễn là bạn đưa ra quyết định toàn dự án ("Dự án của chúng tôi sử dụng STL rộng rãi và chúng tôi không muốn phải thêm trước tất cả mọi thứ với std ::."), Tôi không thấy vấn đề với nó . Điều duy nhất bạn đang mạo hiểm là va chạm tên, sau khi tất cả, và với sự phổ biến của STL nó không có khả năng là một vấn đề.

Mặt khác, nếu đó là quyết định của một nhà phát triển trong một tệp tiêu đề duy nhất (không riêng tư), tôi có thể thấy nó sẽ tạo ra sự nhầm lẫn giữa nhóm và nên tránh như thế nào.

20

mục 59 trong Sutter và Alexandrescu của "C++ Coding tiêu chuẩn: 101 Quy định, Hướng dẫn và Thực tiễn tốt nhất":

  1. Don’t write namespace usings in a header file or before an #include. 108

Các tiêu đề của tất cả các hướng dẫn đang ở http://www.gotw.ca/publications/c++cs.htm, nhưng các chi tiết là một cuốn sách phải đọc cho các nhà phát triển C++.

6

Kiểm tra các tiêu chuẩn mã hóa Trung tâm chuyến bay không gian Goddard (cho C và C++). Đó hóa ra là khó khăn hơn một chút so với trước kia nữa - xem các câu trả lời được cập nhật cho các câu hỏi SO:

Các GSFC C++ mã hóa tiêu chuẩn nói:

§3.3.7 Each header file shall #include the files it needs to compile, rather than forcing users to #include the needed files. #includes shall be limited to what the header needs; other #includes should be placed in the source file.

Câu hỏi được tham chiếu chéo đầu tiên hiện bao gồm trích dẫn từ tiêu chuẩn mã hóa GSFC C và lý do cơ bản, nhưng chất kết thúc lên bei ng như vậy.

2

Tôi tin rằng bạn có thể sử dụng 'sử dụng' trong tiêu đề C++ một cách an toàn nếu bạn viết tờ khai của bạn trong một namespace lồng nhau như thế này:

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED 
{ 
    /*using statements*/ 

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED 
    { 
     /*declarations*/ 
    } 
} 

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED; 

này nên chỉ bao gồm những điều tuyên bố trong 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' mà không có không gian tên sử dụng . Tôi đã thử nghiệm nó trên trình biên dịch mingw64.

+0

Đây là một kỹ thuật hữu ích mà tôi chưa từng thấy trước đây; cảm ơn. Bình thường, tôi đã sử dụng đầy đủ trình độ phạm vi, và đặt các khai báo 'using' bên trong các định nghĩa hàm nơi tôi có thể để chúng không gây ô nhiễm không gian tên bên ngoài hàm. Nhưng bây giờ tôi muốn sử dụng C++ 11 literals do người dùng định nghĩa trong một tệp tiêu đề, và theo quy ước thông thường, các toán tử theo nghĩa đen được bảo vệ bởi một không gian tên; nhưng tôi không thể sử dụng chúng trong danh sách khởi tạo của hàm dựng không nằm trong phạm vi mà tôi có thể sử dụng khai báo 'using' không gây ô nhiễm. Vì vậy, điều này là rất tốt để giải quyết vấn đề đó. –

+0

Mặc dù một hiệu ứng phụ không may của mẫu này là bất kỳ lớp nào được khai báo bên trong không gian tên trong cùng sẽ hiển thị trong thông báo lỗi trình biên dịch với tên đầy đủ: 'error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED :: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED :: ClassName ...'. Ít nhất, đó là những gì đang xảy ra với tôi trong g ++. –

2

Liên quan đến "Có cách nào để hoàn tác [tuyên bố using] không?"

Tôi nghĩ hữu ích khi chỉ ra rằng các tuyên bố using bị ảnh hưởng bởi phạm vi.

#include <vector> 

{ // begin a new scope with { 
    using namespace std; 
    vector myVector; // std::vector is used 
} // end the scope with } 

vector myOtherVector; // error vector undefined 
std::vector mySTDVector // no error std::vector is fully qualified 

Vì vậy, có hiệu quả. Bằng cách giới hạn phạm vi của tuyên bố using, hiệu quả của nó chỉ kéo dài trong phạm vi đó; nó được 'hoàn tác' khi phạm vi đó kết thúc.

Khi khai báo using được khai báo trong tệp bên ngoài bất kỳ phạm vi nào khác, nó có phạm vi tệp và ảnh hưởng đến mọi thứ trong tệp đó.

Trong trường hợp của một tập tin header, nếu việc kê khai using là tại file-phạm vi này sẽ mở rộng phạm vi của bất kỳ tập tin header được bao gồm trong.

+0

bạn dường như là người duy nhất hiểu được câu hỏi thực tế ... tuy nhiên, biên dịch của tôi không phải là rất hạnh phúc về tôi bằng cách sử dụng bên trong giảm tốc lớp. – rustypaper

Các vấn đề liên quan