Sử dụng không gian tên std


110

Dường như có những quan điểm khác nhau về việc sử dụng 'using' đối với không gian tên std.

Một số người nói sử dụng ' using namespace std', người khác nói không, nhưng thay vì các hàm std tiền tố được sử dụng với ' std::' trong khi những người khác nói sử dụng một cái gì đó như thế này:

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

cho tất cả các hàm std sẽ được sử dụng.

Ưu và nhược điểm của từng loại là gì?




Câu trả lời:


131

Hầu hết người dùng C ++ đều khá hài lòng khi đọc std::string, std::vectorv.v. Thực tế, việc nhìn thấy một bản thô vectorkhiến tôi tự hỏi liệu đây có phải là do std::vectorngười dùng định nghĩa hay không vector.

Tôi luôn chống lại việc sử dụng using namespace std; . Nó nhập tất cả các loại tên vào không gian tên chung và có thể gây ra tất cả các loại mơ hồ không rõ ràng.

Dưới đây là một số số nhận dạng phổ biến trong stdkhông gian tên: đếm, sắp xếp, tìm, bằng, đảo ngược. Có một biến cục bộ được gọi countcó nghĩa là using namespace stdsẽ không cho phép bạn sử dụng countthay thế std::count.

Ví dụ cổ điển về xung đột tên không mong muốn là một cái gì đó như sau. Hãy tưởng tượng rằng bạn là một người mới bắt đầu và không biết về std::count. Hãy tưởng tượng rằng bạn đang sử dụng thứ gì đó khác trong <algorithm>hoặc nó bị kéo vào bởi một tiêu đề dường như không liên quan.

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

Lỗi thường dài và không thân thiện vì std::countlà một mẫu có một số kiểu dài được lồng vào nhau.

Tuy nhiên, điều này là OK, bởi vì std::countnó đi vào không gian tên chung và số hàm ẩn nó.

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

Có lẽ hơi ngạc nhiên, điều này là OK. Các số nhận dạng được nhập vào phạm vi khai báo xuất hiện trong không gian tên chung bao quanh cả nơi chúng được xác định và nơi chúng được nhập vào. Nói cách khác, std::counthiển thị như counttrong không gian tên chung, nhưng chỉ hiển thị bên trong increment.

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

Và vì những lý do tương tự, countrất mơ hồ ở đây. using namespace stdkhông gây ra std::count, ẩn bên ngoài countnhư nó có thể được mong đợi. Các using namespacephương tiện cai trị rằng std::countvẻ bề ngoài (trong incrementchức năng) như thể nó đã được khai báo ở phạm vi toàn cầu, tức là ở phạm vi tương tự như int count = 0;và do đó gây ra sự mơ hồ.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}

21
nhưng nó gõ soooo dễ dàng hơn nhiều mà không có tiền tố std ::!
xtofl

69
@xtofl: Không, không. Năm ký tự không liên quan lắm khi nhập, nhưng năm ký tự này có thể rất phù hợp khi đọc. Và tính dễ đọc hơn nhiều so với việc dễ nhập đối với mã nguồn, vì mã được đọc nhiều hơn được viết.
sbi

3
Bạn có thể thêm rằng câu lệnh using hoạt động đúng với các quy tắc phạm vi.
Martin York

2
@Martin York: Đã cập nhật các ví dụ minh họa các quy tắc xác định phạm vi. @Michael Burr: Điều đó được cho là không quá tệ, điều tôi thực sự không thích là nơi các thông báo lỗi cho những lỗi đơn giản khó hiểu hơn rất nhiều, hoặc nơi chúng hoàn toàn không xảy ra. Ví dụ: nếu một hàm được cho là nằm trong phạm vi, nhưng không phải và hàm std :: thì thay vì nhận được lỗi hữu ích 'không nhận dạng được mã định danh', bạn thường gặp phải đối số không thể chuyển đổi 'khó hiểu hơn Lỗi kiểu X 'hoặc' không thể tạo hàm từ mẫu '. Tệ hơn nữa là nếu một hàm sai được gọi âm thầm. Nó hiếm, nhưng xảy ra.
CB Bailey

5
Vâng, tôi ngạc nhiên là không ai thảo luận về tùy chọn của using std::xxx;. Nó không gây ô nhiễm không gian tên, việc viết mã sẽ ngắn hơn và tôi nghĩ copylà dễ đọc hơn rất nhiều std::copy.
Legends2k

41

Loại trừ những điều cơ bản (Phải thêm std :: infront của tất cả các đối tượng / hàm stl và ít có nguy cơ xung đột hơn nếu bạn không có 'using namespace std')

Cũng cần lưu ý rằng bạn không bao giờ nên đặt

using namespace std

Trong tệp tiêu đề, vì nó có thể truyền đến tất cả các tệp bao gồm tệp tiêu đề đó, ngay cả khi họ không muốn sử dụng không gian tên đó.

Trong một số trường hợp, sử dụng những thứ như

using std::swap

Như thể có một phiên bản hoán đổi chuyên biệt, trình biên dịch sẽ sử dụng phiên bản đó, nếu không nó sẽ hoạt động trở lại std::swap.

Nếu bạn gọi std::swap, bạn luôn sử dụng phiên bản cơ bản, phiên bản này sẽ không gọi phiên bản tối ưu hóa (nếu nó tồn tại).


10
+1 để đề cập using std::swap(đó là thứ duy nhất tôi từng sử dụng).
sbi

1
+1 cho đề cập u n scó thể lan truyền. Chỉ cần lưu ý rằng nó cũng có thể đi sâu vào các tiêu đề được xây dựng chính xác: Chúng chỉ phải được đưa vào sau một tiêu đề giả mạo.
quamrana

1
Nhưng nếu bạn đang xác định một swaphoặc move(hoặc hash, lessv.v.) chuyên môn, bạn nên đưa chuyên môn đó vào namespace std. Ví dụ:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
AJMansfield

28

Đầu tiên, một số thuật ngữ:

  • using-khai báo : using std::vector;
  • using-chỉ thị : using namespace std;

Tôi nghĩ rằng việc sử dụng các chỉ thị using cũng được, miễn là chúng không được sử dụng ở phạm vi toàn cục trong một tệp tiêu đề. Vì vậy, có

using namespace std;

trong tệp .cpp của bạn không thực sự là một vấn đề và nếu nó xảy ra, nó hoàn toàn nằm trong tầm kiểm soát của bạn (và thậm chí nó có thể được xác định phạm vi đến các khối cụ thể nếu muốn). Tôi không thấy lý do cụ thể nào để làm lộn xộn mã với một loạt các std::vòng loại - nó chỉ trở thành một đống nhiễu trực quan. Tuy nhiên, nếu bạn không sử dụng toàn bộ tên từ stdkhông gian tên trong mã của mình, tôi cũng không thấy vấn đề gì với việc loại bỏ chỉ thị. Đó là một sự phản phục - nếu chỉ thị không cần thiết, thì không cần sử dụng nó.

Tương tự như vậy, nếu bạn có thể sử dụng một số khai báo bằng cách sử dụng (thay vì sử dụng chỉ thị ) cho các kiểu cụ thể trong stdkhông gian tên, thì không có lý do gì bạn không nên chỉ đưa những tên đặc biệt đó vào không gian tên hiện tại. Tương tự như vậy, tôi nghĩ sẽ thật điên rồ và rắc rối trong việc ghi sổ kế toán khi có 25 hoặc 30 khai báo sử dụng khi một chỉ thị sử dụng duy nhất cũng thực hiện thủ thuật.

Cũng nên nhớ rằng đôi khi bạn phải sử dụng khai báo using. Tham khảo "Mục 25: Xem xét hỗ trợ cho một giao dịch hoán đổi không ném" từ C ++ hiệu quả, Phiên bản thứ ba. Để có một hàm mẫu, chung chung sử dụng phương pháp hoán đổi 'tốt nhất' cho một kiểu tham số, bạn cần sử dụng tra cứu phụ thuộc vào khai báo và đối số (còn gọi là tra cứu ADL hoặc Koenig):

template< typename T >
void foo( T& x, T& y)
{
    using std::swap;     // makes std::swap available in this function

    // do stuff...

    swap( x, y);         // will use a T-specific swap() if it exists,
                         //  otherwise will use std::swap<T>()

    // ...
 }

Tôi nghĩ chúng ta nên xem xét các thành ngữ phổ biến cho các ngôn ngữ khác nhau sử dụng không gian tên đáng kể. Ví dụ, Java và C # sử dụng không gian tên ở một mức độ lớn (được cho là nhiều hơn C ++). Cách phổ biến nhất mà tên trong không gian tên được sử dụng trong các ngôn ngữ đó là đưa chúng vào phạm vi hiện tại hàng loạt với tương đương với chỉ thị sử dụng. Điều này không gây ra các vấn đề trên diện rộng và một vài lần vấn đề được xử lý trên cơ sở 'ngoại lệ' bằng cách xử lý các tên được đề cập thông qua các tên đủ điều kiện hoặc bằng bí danh - giống như có thể được thực hiện trong C ++.

Herb Sutter và Andrei Alexandrescu có điều này để nói trong "Mục 59: Không viết sử dụng không gian tên trong tệp tiêu đề hoặc trước #include" của cuốn sách của họ, Tiêu chuẩn mã hóa C ++: 101 Quy tắc, Nguyên tắc và Thực tiễn Tốt nhất:

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 #includecác lệnh và cảm thấy hài lòng về nó. Mặc dù có 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.

Stroupstrup thường được trích dẫn câu nói, "Đừng làm ô nhiễm không gian tên chung", trong "Ngôn ngữ lập trình C ++, phiên bản thứ ba". Trên thực tế, anh ta nói điều đó (C.14 [15]), nhưng đề cập đến chương C.10.1, nơi anh ta nói:

Một khai báo using thêm tên vào một phạm vi cục bộ. Một chỉ thị sử dụng không; nó chỉ hiển thị các tên có thể truy cập được trong phạm vi mà chúng đã được khai báo. Ví dụ:

namespaceX {
    int i , j , k ;
}

int k ;
void f1()
{
    int i = 0 ;

    using namespaceX ; // make names from X accessible

    i++; // local i
    j++; // X::j
    k++; // error: X::k or global k ?

    ::k ++; // the global k

    X::k ++; // X’s k
}

void f2()
{
    int i = 0 ;

    using X::i ; // error: i declared twice in f2()
    using X::j ;
    using X::k ; // hides global k

    i++;
    j++; // X::j
    k++; // X::k
}

Tên được khai báo cục bộ (được khai báo bởi một khai báo thông thường hoặc bởi một khai báo sử dụng) ẩn các khai báo phi địa phương của cùng một tên và bất kỳ sự quá tải bất hợp pháp nào của tên đều được phát hiện tại điểm khai báo.

Lưu ý lỗi không rõ ràng cho k++in f1(). Tên chung không được ưu tiên so với tên từ không gian tên có thể truy cập được trong phạm vi toàn cầu. Điều này cung cấp sự bảo vệ đáng kể chống lại các cuộc đụng độ tên ngẫu nhiên, và - quan trọng - đảm bảo rằng không có lợi thế nào đạt được từ việc làm ô nhiễm không gian tên toàn cầu.

Khi các thư viện khai báo nhiều tên được làm cho có thể truy cập được thông qua các chỉ thị sử dụng, thì đó là một lợi thế đáng kể mà các xung đột của các tên không sử dụng không bị coi là lỗi.

...

Tôi hy vọng sẽ thấy việc sử dụng tên chung trong các chương trình mới sử dụng không gian tên giảm hẳn so với các chương trình C và C ++ truyền thống. Các quy tắc cho không gian tên được thiết kế đặc biệt để không mang lại lợi ích cho người dùng tên toàn cầu '' lười biếng '' so với người cẩn thận không làm ô nhiễm phạm vi toàn cầu.

Và làm thế nào một người có lợi thế giống như một 'người lười biếng của tên toàn cầu'? Bằng cách tận dụng chỉ thị using, lệnh này làm cho các tên trong vùng tên có sẵn cho phạm vi hiện tại một cách an toàn .

Lưu ý rằng có một sự khác biệt - các tên trong stdkhông gian tên được tạo sẵn cho một phạm vi với việc sử dụng thích hợp chỉ thị sử dụng (bằng cách đặt chỉ thị sau dấu #includes) sẽ không gây ô nhiễm không gian tên chung. Nó chỉ làm cho những tên đó có sẵn một cách dễ dàng và với sự bảo vệ liên tục chống lại các cuộc đụng độ.


Liên quan đến điểm cuối cùng của bạn: Java và C # cũng có không gian tên gọn gàng hơn nhiều. Nếu mọi thứ trong BCL nằm trong Hệ thống, thì việc "sử dụng Hệ thống" sẽ gây ra nhiều rắc rối giống như "sử dụng không gian tên std".
Jeff Hardy

Nhưng các chương trình Java và C # mà tôi thấy thường mang lại tất cả các không gian tên mà chúng sử dụng - không chỉ "Hệ thống" (hoặc tương đương). Vì vậy, thay vì một chỉ thị sử dụng duy nhất mang lại tất cả các tên được sử dụng, có 5 hoặc 10 chỉ thị thực hiện nhiều hơn hoặc ít hơn điều tương tự. Ngoài ra, "using namespace std;" thực sự gây ra nhiều rắc rối?
Michael Burr

Vấn đề là std có quá nhiều tên phổ biến và bao gồm một tiêu đề tiêu chuẩn có thể bao gồm tất cả các tên khác. Chúng ta không kiểm soát tốt những gì được nhập khẩu, có quá nhiều rủi ro. Tôi không biết đầy đủ về Java và C #, nhưng tôi biết về Ada có hệ thống mô-đun tốt hơn nhiều so với C ++ và nơi nhập tên thường bị khó chịu. Nói chung, vấn đề đầu tiên là quy ước đặt tên (tôi đã thấy mọi người sử dụng tiền tố cũng như không gian tên, không nhập không có ý nghĩa) sau đó là kiểu.
AProgrammer

1
Tôi vẫn không tin rằng đây là một vấn đề trong thế giới thực. Tôi thấy các chỉ thị sử dụng được sử dụng mọi lúc mà không có nhược điểm nghiêm trọng. Sau đó, một lần nữa, tôi không có vấn đề gì với việc không sử dụng chúng. Tôi chỉ thích rằng các định nghĩa std::không làm lộn xộn mã - có những cách khác để tránh điều đó (sử dụng khai báo hoặc typedef thường làm thủ thuật).
Michael Burr

1
@AProgrammer: bạn nói, "danh sách là số nhận dạng tự nhiên để xác định danh sách trong trình thông dịch ngọng" - nhưng có lệnh " using namespace std;" không ngăn bạn khai báo số nhận dạng tự nhiên của mình ' list' - chỉ là nếu bạn làm vậy, bạn không thể sử dụng lâu hơn std::listmà không đủ điều kiện. Điều đó không khác gì nếu không có using namespace std;chỉ thị "". Hay tôi đang thiếu cái gì đó?
Michael Burr

17

Không bao giờ sử dụng bằng cách sử dụng không gian tên ở phạm vi toàn cầu trong tệp tiêu đề. Điều đó có thể dẫn đến xung đột và người phụ trách hồ sơ nơi xung đột xuất hiện không kiểm soát được nguyên nhân.

Trong tệp triển khai, các lựa chọn ít bị cắt hơn nhiều.

  • Đặt std không gian tên bằng cách sử dụng sẽ mang tất cả các ký hiệu từ không gian tên đó. Điều này có thể gây rắc rối vì gần như không có cơ quan nào biết tất cả các ký hiệu ở đó (vì vậy không thể áp dụng chính sách không xung đột trong thực tế) nếu không nói về các ký hiệu sẽ được thêm vào. Và tiêu chuẩn C ++ cho phép tiêu đề thêm ký hiệu từ các tiêu đề khác (tiêu chuẩn C không cho phép điều đó). Nó vẫn có thể hoạt động tốt trong thực tế để đơn giản hóa việc viết trong trường hợp được kiểm soát. Và nếu một lỗi xảy ra, nó được phát hiện trong tệp có vấn đề.

  • Đặt bằng cách sử dụng std :: name; có lợi thế là viết đơn giản mà không có rủi ro nhập các ký hiệu không xác định. Cái giá phải trả là bạn phải nhập tất cả các ký hiệu mong muốn một cách rõ ràng.

  • Đủ điều kiện rõ ràng thêm một chút lộn xộn, nhưng tôi nghĩ rằng đó là một số thực hành ít rắc rối hơn.

Trong dự án của tôi, tôi sử dụng chứng chỉ rõ ràng cho tất cả các tên, tôi chấp nhận sử dụng std :: name, tôi chống lại việc sử dụng không gian tên std (chúng tôi có một trình thông dịch lisp có kiểu danh sách riêng của mình và do đó xung đột là điều chắc chắn).

Đối với các không gian tên khác, bạn cũng phải tính đến các quy ước đặt tên được sử dụng. Tôi biết về một dự án sử dụng không gian tên (để phiên bản) và tiền tố trên tên. Thực hiện using namespace Xsau đó gần như không có rủi ro và không làm điều đó dẫn đến mã trông ngu ngốc PrefixNS::pfxMyFunction(...).

Có một số trường hợp bạn muốn nhập các ký hiệu. std :: swap là trường hợp phổ biến nhất: bạn nhập std :: swap và sau đó sử dụng swap không đủ tiêu chuẩn. Tra cứu phụ thuộc đối số sẽ tìm thấy một hoán đổi thích hợp trong không gian tên của kiểu nếu có và trở lại mẫu chuẩn nếu không có.


Biên tập:

Trong phần bình luận, Michael Burr tự hỏi liệu xung đột có xảy ra trong thế giới thực hay không. Đây là một ví dụ thực tế trực tiếp. Chúng tôi có một ngôn ngữ mở rộng với là một phương ngữ ngọng. Trình thông dịch của chúng tôi có tệp bao gồm, lisp.h chứa

typedef struct list {} list;

Chúng tôi đã phải tích hợp và điều chỉnh một số mã (mà tôi sẽ đặt tên là "engine") trông như thế này:

#include <list>
...
using std::list;
...
void foo(list const&) {}

Vì vậy, chúng tôi đã sửa đổi như thế này:

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

Tốt. Mọi thứ đều hoạt động. Vài tháng sau, "module.h" đã được sửa đổi để bao gồm "list.h". Các bài kiểm tra đã thông qua. "mô-đun" không được sửa đổi theo cách ảnh hưởng đến ABI của nó, vì vậy, thư viện "động cơ" có thể được sử dụng mà không cần biên dịch lại người dùng của nó. Kiểm tra tích hợp là OK. "Mô-đun" mới được xuất bản. Quá trình biên dịch tiếp theo của engine đã bị phá vỡ khi mã của nó chưa được sửa đổi.


1
Một trong những trường hợp được kiểm soát mà tôi nghĩ rằng việc sử dụng không gian tên được chấp nhận là trong xuất bản mã. Việc đơn giản hóa tạo điều kiện thuận lợi cho bố cục của trang và giúp tập trung vào điểm tiếp xúc. Hạn chế là nó không thực sự cho thấy một cách thực hành tốt, vì vậy tôi sẽ không sử dụng nó trong sách dành cho người mới bắt đầu.
AProgrammer

1
Tôi nghĩ gõ std :: là một giá nhỏ để trả cho rõ ràng
paoloricardo

4
@paoloricardo: Mặt khác, tôi nghĩ rằng việc có std :: hiển thị khắp nơi là một sự lộn xộn không cần thiết về mặt hình ảnh.
Michael Burr

1
@Michael: bạn trả tiền và bạn lựa chọn!
paoloricardo

2
Cảm ơn bạn đã dành thời gian để thêm chi tiết về vấn đề bạn gặp phải.
Michael Burr

4

Nếu bạn không có nguy cơ xung đột tên trong mã của mình với std và các thư viện khác, bạn có thể sử dụng:

using namespace std;

Nhưng nếu bạn muốn biết chính xác mức độ phụ thuộc của mã để làm tài liệu hoặc có nguy cơ xung đột tên, hãy sử dụng theo cách khác:

using std::string;
using std::cout;

Giải pháp thứ ba, không sử dụng các giải pháp này và viết std :: trước mỗi lần sử dụng trong mã sẽ mang lại cho bạn sự bảo mật hơn nhưng, có thể một chút nghiêm trọng trong mã ...


4

Cả hai

using std::string;

using namespace std;

thêm một số ký hiệu (một hoặc nhiều) vào không gian tên chung. Và thêm ký hiệu vào không gian tên chung là điều bạn không bao giờ nên làm trong các tệp tiêu đề. Bạn không có quyền kiểm soát ai sẽ bao gồm tiêu đề của bạn, có rất nhiều tiêu đề bao gồm các tiêu đề khác (và tiêu đề bao gồm tiêu đề bao gồm tiêu đề và v.v.).

Trong các tệp triển khai (.cpp), tùy thuộc vào bạn (chỉ nhớ thực hiện điều đó sau tất cả các lệnh #include). Bạn chỉ có thể phá vỡ mã trong tệp cụ thể này, do đó, việc quản lý và tìm ra lý do xung đột tên sẽ dễ dàng hơn. Nếu bạn thích sử dụng std :: (hoặc bất kỳ tiền tố nào khác, có thể có nhiều không gian tên trong dự án của bạn) trước các phân số, thì không sao. Nếu bạn muốn thêm số nhận dạng mà bạn sử dụng vào không gian tên chung, không sao cả. Nếu bạn muốn mang toàn bộ không gian tên lên đầu :-), điều đó tùy thuộc vào bạn. Mặc dù các hiệu ứng được giới hạn trong đơn vị biên dịch duy nhất, nhưng nó có thể chấp nhận được.


3

Đối với tôi, tôi thích sử dụng ::khi có thể.

std::list<int> iList;

Tôi ghét viết:

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

Hy vọng rằng, với C ++ 0x tôi sẽ viết thế này:

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

Nếu không gian tên quá dài,

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}

@AraK: không gian tên dir = boost :: filesystem; Tôi đoán đây là một bí danh?
paoloricardo

@paoloricardo: Vâng, đó là những gì nó là.
sbi

2
Các trình lặp nên được tăng dần ++i, không phải i++bởi vì, nếu nó thậm chí được xác định, sẽ tạo ra một bản sao tạm thời không cần thiết của trình lặp.
Felix Dombek,

2

Bạn không bao giờ nên using namespace stdở phạm vi không gian tên trong tiêu đề. Ngoài ra, tôi cho rằng hầu hết các lập trình viên sẽ tự hỏi khi họ nhìn thấy vectorhoặc stringkhông có std::, vì vậy tôi nghĩ không phải using namespace stdlà tốt hơn. Vì vậy, tôi tranh luận là không bao giờ có using namespace std.

Nếu bạn muốn, hãy thêm cục bộ bằng cách sử dụng các khai báo như using std::vector. Nhưng hãy tự hỏi: Điều này có giá trị gì? Một dòng mã được viết một lần (có thể hai lần), nhưng nó được đọc mười, trăm hoặc nghìn lần. Nỗ lực nhập đã tiết kiệm được để thêm một khai báo hoặc chỉ thị bằng cách sử dụng là rất nhỏ so với nỗ lực đọc mã.

Với ý nghĩ đó, trong một dự án mười năm trước, chúng tôi đã quyết định xác định rõ ràng tất cả các định danh có tên không gian tên đầy đủ của chúng. Điều có vẻ khó xử lúc đầu đã trở thành thông lệ trong vòng hai tuần. Bây giờ, trong tất cả các dự án của toàn bộ công ty đó, không ai còn sử dụng lệnh hoặc khai báo nữa. (Với một ngoại lệ, hãy xem bên dưới.) Nhìn vào mã (vài MLoC) sau mười năm, tôi cảm thấy như chúng tôi đã quyết định đúng.

Tôi nhận thấy rằng thông thường, những người phản đối lệnh cấm usingthường không thử nó cho một dự án. Những người đã thử, thường thấy nó tốt hơn so với việc sử dụng các chỉ thị / khai báo sau một thời gian rất ngắn.

Lưu ý: Ngoại lệ duy nhất using std::swaplà cần thiết (đặc biệt là trong mã chung) để nhận các quá tải swap()không thể đưa vào stdkhông gian tên (vì chúng tôi không được phép đặt quá tải stdhàm vào không gian tên này).


3
Một chuyên môn hóa của std :: swap sẽ là một chuyên môn hóa hoàn toàn - bạn không thể chuyên môn hóa một phần các mẫu hàm. Bất kỳ chương trình nào cũng được phép chuyên biệt hóa một phần bất kỳ mẫu thư viện tiêu chuẩn nào miễn là chuyên môn hóa đó phụ thuộc vào kiểu do người dùng xác định.
CB Bailey

@Charles: Vâng, bạn nói đúng, tất nhiên, không có FTPS. Và tôi có thể chuyên biệt hóa các mẫu bên trong std, nhưng không quá tải. Xin lỗi vì điều đó. Tôi sẽ sửa bài.
sbi

2
Tôi không nghĩ mục đích của using namespacechỉ thị là để thực hiện việc đánh máy ; đúng hơn, nó là để làm cho việc đọc dễ dàng hơn, bởi vì, như bạn nói, mã đó sẽ phải được đọc hàng chục, hàng trăm hoặc hàng nghìn lần. Và đối với một số người, nó đọc dễ dàng hơn nhiều với ít std::lộn xộn hơn . Nhưng điều đó có lẽ phụ thuộc vào khả năng nhận thức cá nhân; một số người lọc std::bỏ đi hoặc thậm chí cần nó để được hướng dẫn (như serifs), những người khác thì sững sờ với nó và cảm thấy như đang đi trên một con đường gập ghềnh.
Lumi


1
@sbi: Không, điều đó không khách quan. Nó phụ thuộc vào việc bạn nghĩ std :: hữu ích hay lộn xộn. Nhiều lộn xộn -> kém rõ ràng.
Joshua Richardson

2

Không gian tên lưu giữ mã để tránh nhầm lẫnô nhiễm chữ ký hàm.

Đây là một bản trình diễn đầy đủ và được tài liệu hóa về việc sử dụng không gian tên thích hợp :

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see /programming/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Đầu ra:

Our log: 42
Standard log: 1.43508

1

using namespace stdnhập nội dung của stdkhông gian tên trong không gian tên hiện tại. Vì vậy, lợi thế là bạn sẽ không phải nhậpstd:: trước tất cả các hàm của không gian tên đó. Tuy nhiên, có thể xảy ra trường hợp bạn có các không gian tên khác nhau có các chức năng giống tên. Do đó, bạn có thể kết thúc việc không gọi cho người bạn muốn.

Chỉ định thủ công những cái bạn muốn nhập vào std sẽ ngăn điều đó xảy ra, nhưng có thể dẫn đến một danh sách dài sử dụng ở đầu tệp của bạn, điều mà một số nhà phát triển sẽ thấy xấu xí;)!

Cá nhân tôi thích chỉ định không gian tên mỗi khi tôi sử dụng một hàm, ngoại trừ khi không gian tên quá dài, trong trường hợp đó, tôi đặt một số sử dụng ở đầu tệp.

CHỈNH SỬA: như đã lưu ý trong một câu trả lời khác, bạn không bao giờ nên đặt một using namespacetệp tiêu đề trong tệp tiêu đề, vì nó sẽ lan truyền đến tất cả các tệp bao gồm tiêu đề này và do đó có thể tạo ra hành vi không mong muốn.

EDIT2: đã sửa câu trả lời của tôi, nhờ Charles nhận xét.


2
using namespace std;nhập nội dung của stdkhông gian tên vào không gian tên chung. Nó không thay đổi không gian tên mặc định. Việc xác định một cái gì đó trong không gian tên chung sau một using namespace stdsẽ không đưa nó vào stdkhông gian tên một cách kỳ diệu .
CB Bailey

Xin lỗi, đây không phải là ý của tôi. Cảm ơn vì đã chỉ ra, tôi sẽ sửa câu trả lời của mình.
Wookai

1
Guys: cảm ơn vì những câu trả lời. Nói chung, có vẻ như không sử dụng 'using namespace std' sẽ an toàn hơn và tránh tạo ra những sự mơ hồ tiềm ẩn. Về số dư, sử dụng 'std :: xxx' hấp dẫn tôi hơn là khai báo danh sách các chức năng khác nhau ở đầu tệp nguồn vì nó đủ điều kiện rõ ràng mục đích của một người là gì.
paoloricardo

1
Trích dẫn (trừ khi không gian tên quá dài). Bạn có thể sử dụng bí danh không gian tên để trợ giúp ở đó. 'không gian tên Rv1 = Thor :: XML :: XPath :: Quy tắc :: Ánh sáng :: Phiên bản1;' Lưu ý bí danh và sử dụng cả hai đều tuân theo quy tắc xác định phạm vi;
Martin York

0

Giống như trong Java, nơi bạn có thể sử dụng có thể bao gồm java.util. * Hoặc chỉ cần chọn từng lớp riêng lẻ, điều đó tùy thuộc vào phong cách. Lưu ý rằng bạn không muốn một cái using namespace stdở đầu tệp / phạm vi rộng của bạn vì bạn sẽ làm ô nhiễm không gian tên và có thể xảy ra xung đột, đánh bại điểm của không gian tên. Nhưng nếu bạn có một hàm sử dụng nhiều STL, nó sẽ làm xáo trộn mã để có một mớ cú pháp tiền tố trong logic của bạn và bạn có thể nên cân nhắc sử dụng using namespace std(khi sử dụng nhiều lớp) hoặc từng usings (khi sử dụng một vài lớp học thường xuyên).


0

Cuộc thảo luận này sẽ tồn tại miễn là IDE mà bạn làm việc không đủ linh hoạt để hiển thị hoặc ẩn thông tin chính xác bạn cần.

Đó là bởi vì bạn muốn mã của mình trông như thế nào phụ thuộc vào nhiệm vụ đang thực hiện.

Trong khi tạo mã nguồn của mình, tôi muốn xem chính xác lớp nào mình đang sử dụng: là nó std::stringhay là BuzFlox::Obs::stringlớp?

Khi thiết kế luồng điều khiển, tôi thậm chí không quan tâm đến các loại biến, nhưng tôi muốn tập trung vào if's và while' s và continue'.

Vì vậy, đây là lời khuyên của tôi:

Tùy thuộc vào đối tượng của mã và sức mạnh của các công cụ của bạn, hãy chọn cách đọc dễ nhất hoặc cung cấp hầu hết thông tin.


0

Có một số cách để khắc phục điều đó.

Thứ nhất: sử dụng như những gì bạn đã làm.

Thứ hai: làm namespace S = std;, giảm 2 ký tự.

Thứ ba: sử dụng static.

Thứ tư: không sử dụng tên mà stdsử dụng.


-1

Ưu và nhược điểm của từng loại là gì

Lý do duy nhất để bỏ std :: là về lý thuyết, bạn có thể tự thực hiện lại tất cả các chức năng STL. Sau đó, các hàm của bạn có thể được chuyển từ sử dụng std :: vector sang my :: vector mà không cần thay đổi mã.


Không gian tên không thực sự được thiết kế để cho phép thay thế các tên bằng các chức năng khác, nhưng tương đương. Chúng được thiết kế để ngăn chặn các cuộc đụng độ tên ngoài ý muốn.
Michael Burr

Có, vì vậy, lý do duy nhất cho lệnh 'using' phá vỡ điều này là cho phép bạn chuyển các chức năng sang một vùng tên mới.
Martin Beckett

Tôi nghĩ rằng bạn sẽ thấy rất nhiều lập trình viên phàn nàn về những khó khăn trong không gian tên ass là gì và muốn ném chúng ra ngoài cửa sổ nếu không có chỉ thị sử dụng. Theo như tôi biết, mọi ngôn ngữ sử dụng không gian tên đều có một cái gì đó tương tự như một chỉ thị sử dụng để giúp chúng tránh khỏi việc sử dụng khi bạn muốn chúng tránh khỏi việc sử dụng. Nếu các chỉ thị là vô ích, tại sao chúng tồn tại ở khắp mọi nơi?
Michael Burr

Tôi nghĩ rằng "using" nhằm cho phép bạn chuyển sang các triển khai thay thế hơn là để tiết kiệm việc gõ 3 chữ cái. Tôi thích sử dụng "std :: Foo" vì nó phục vụ như một hợp đồng với lập trình viên rằng tôi đang sử dụng Foo bình thường và họ không phải kiểm tra. Tôi đồng ý rằng tôi sẽ không muốn phải nhập "com.microsoft.visual-studio.standard-library.numbers.int foo", một số khai báo trình lặp trong STL nhận được như thế này. Python thực hiện một công việc tốt khi cho phép bạn kéo các bộ hàm được trang trí hoặc chưa được trang trí từ các mô-đun.
Martin Beckett

-1

Tại sao không ví dụ

typedef std::vector<int> ints_t;
ints_t ints1;
....
ints_t ints2;

thay vì khó sử dụng

std::vector<int> ints1;
...
std::vector<int> ints2;

Tôi thấy nó dễ đọc hơn nhiều và nó là tiêu chuẩn viết mã của tôi.

Bạn thậm chí có thể sử dụng nó để bao gồm một số thông tin ngữ nghĩa cho người đọc. Ví dụ, hãy xem xét các nguyên mẫu hàm

void getHistorgram(std::vector<unsigned int>&, std::vector<unsigned int>&);

cái nào giá trị trả về?

Thay vào đó thì sao

typedef std::vector<unsigned int> values_t;
typedef std::vector<unsigned int> histogram_t;
...
void getHistogram(values_t&, histogram_t&); 
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.