Tôi có nên sử dụng tính năng 'tự động' mới của C ++ 11, đặc biệt là trong các vòng lặp không?


20

Những ưu / nhược điểm khi sử dụng autotừ khóa, đặc biệt là trong các vòng lặp là gì?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

Có vẻ như nếu bạn không biết liệu bạn có một iterator cho một bản đồ hoặc một vector bạn sẽ không biết liệu có nên sử dụng firsthay secondhay chỉ trực tiếp các thuộc tính truy cập của đối tượng, đúng không?

Điều này nhắc nhở tôi về cuộc tranh luận về C # về việc có nên sử dụng từ khóa hay không var. Ấn tượng tôi nhận được cho đến nay là trong thế giới C ++, mọi người sẵn sàng chấp nhận autotừ khóa với ít cuộc chiến hơn vartrong thế giới C #. Đối với tôi, bản năng đầu tiên của tôi là tôi muốn biết loại biến để tôi có thể biết những thao tác nào tôi có thể mong đợi để thực hiện trên nó.


3
Chờ đợi! Có một cuộc chiến về việc có nên sử dụng var? Tôi bỏ lỡ điều đó.
pdr

21
Thậm chí tốt hơn, bạn chỉ có thể sử dụng for (auto& it : x)(hoặc không có tài liệu tham khảo nếu bạn muốn sao chép)
Tamás Szelei

7
Có vẻ với tôi nếu bạn đang viết một vòng lặp để lặp lại nội dung xvà thậm chí bạn không biết đó xlà gì , bạn không nên viết vòng lặp đó ở vị trí đầu tiên ;-)
nikie

@fish: phạm vi dựa trên quy tắc cho vòng lặp, nhưng tôi sẽ có phạm vi và thực hiện: 'for (T & it: x)' thay vì khi sử dụng phạm vi dựa trên vòng lặp, vì tôi cảm thấy sử dụng tự động có ít thông tin hơn. Loại lạm dụng tự động trong tâm trí của tôi.
martiert

Cuộc chiến về việc sử dụng var là một chút ngớ ngẩn, đặc biệt là nhìn lại. Xem chương trình vận chuyển hàng hóa .
Craig

Câu trả lời:


38

Các động lực trong C ++ là cực đoan hơn, vì các loại có thể trở nên phức tạp và phức tạp hơn nhiều so với các loại C # do siêu lập trình và những thứ khác. autonhanh hơn để viết và đọc và linh hoạt / duy trì hơn một loại rõ ràng. Ý tôi là, bạn có muốn bắt đầu gõ không

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

Đó thậm chí không phải là loại đầy đủ. Tôi đã bỏ lỡ một vài đối số mẫu.


8
+1 cho ví dụ, nhưng điều đó cũng cho biết điều gì đó về trạng thái của C ++ "hiện đại".
zvrba

22
@zvrba: Vâng- rằng các cơ sở chung mạnh hơn nhiều so với C #.
DeadMG

4
đó là những gì typedef dành cho
gbjbaanb

19
@gbjbaanb Không, đó là những gì autodành cho. Thiết kế bởi. typedefgiúp, nhưng autogiúp nhiều hơn.
Konrad Rudolph

1
typedef làm mất hiệu lực đối số rằng "không sử dụng tự động tạo ra các loại thực sự dài"
Michael

28

Trong ví dụ của bạn:

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

phải có một tuyên bố để xnhìn thấy. Do đó loại itnên rõ ràng. Nếu loại xkhông rõ ràng, thì phương thức này quá dài hoặc lớp quá lớn.


7
Ngoài ra, xlà một tên biến rất xấu cho một container. Trong một số tình huống, rất có thể bạn chỉ cần nhìn vào tên (có giá trị về mặt ngữ nghĩa) và suy ra các hoạt động có thể.
Tối đa

@Max: chỉ được sử dụng xnhư một ví dụ chung, tôi có xu hướng sử dụng các tên biến khá mô tả.
Người dùng

@ Người dùng Tất nhiên, tôi không cho rằng đó là một ví dụ trong thế giới thực;)
Tối đa

14

Phản đối ! Câu hỏi được tải.

Bạn có thể giải thích cho tôi tại sao mã thứ ba có ??trong đó, nhưng mã thứ nhất và thứ hai thì không? Để công bằng, mã của bạn phải đọc như sau:

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

Đó Vấn đề tương tự mặc dù bạn không sử dụngauto .

Và trong mọi trường hợp, câu trả lời là như nhau: Các vấn đề bối cảnh . Bạn không thể nói một cách có ý nghĩa về một đoạn mã riêng lẻ. Ngay cả khi bạn đã không sử dụng các mẫu nhưng một số loại cụ thể, điều này sẽ chỉ chuyển vấn đề sang một nơi khác, vì người đọc mã của bạn sẽ phải biết về khai báo loại đã nói.

Nếu sử dụng auto trong các tình huống đó khiến mã của bạn không thể đọc được, bạn nên coi đây là một dấu hiệu cảnh báo rằng có gì đó không đúng với thiết kế mã của bạn. Tất nhiên, có những trường hợp chi tiết cấp thấp quan trọng (chẳng hạn như khi xử lý các hoạt động bit hoặc API kế thừa) trong trường hợp một loại rõ ràng có thể hỗ trợ khả năng đọc. Nhưng nói chung - không.

Về var(vì bạn đã đề cập rõ ràng về nó), cũng có một sự đồng thuận lớn trong cộng đồng C # để sử dụng var. Các lập luận chống lại việc sử dụng nó thường được xây dựng trên các ngụy biện .


1
Tôi nghĩ vấn đề là, với auto bạn không biết mình đặt cái gì tiếp theo ... đó là mã cụ thể của bạn "cái gì đó" hay nó là một kiểu dữ liệu liên quan đến việc giải nén để đến đối tượng dữ liệu của bạn có phương thức "cái gì đó"
Michael Shaw

1
@Ptolemy Và quan điểm của tôi là: trong hai mã còn lại, bạn cũng không biết (nói chung) nên đặt cái gì tiếp theo: Tkhông rõ ràng đối với người dùng auto. Tuy nhiên, một người được cho là ổn còn người kia thì không?! Điều đó không có ý nghĩa. Trong trường hợp của OP, Tlà một thay thế cho một loại tùy ý. Trong mã thực, nó có thể là việc sử dụng các mẫu (for typename std::vector<T>::iterator…)hoặc giao diện lớp. Trong cả hai trường hợp, loại thực tế bị ẩn khỏi người dùng và chúng tôi thường xuyên viết mã như vậy mà không gặp vấn đề gì.
Konrad Rudolph

1
Trên thực tế, có bạn làm. Nếu đó là một vectơ, bạn biết rằng bạn cần phải làm -> và sau đó bạn có quyền truy cập vào loại dữ liệu của mình. Nếu là bản đồ, bạn biết bạn cần phải làm -> thứ hai-> và sau đó bạn có quyền truy cập vào loại dữ liệu của mình, nếu tự động, bạn không biết bạn cần làm gì để có quyền truy cập vào loại dữ liệu của mình. Bạn dường như đang nhầm lẫn giữa "loại dữ liệu có trong bộ sưu tập STL" với "loại bộ sưu tập STL nào chúng ta có". tự động làm cho vấn đề này tồi tệ hơn.
Michael Shaw

1
@Ptolemy Tất cả những lập luận này đều đúng như khi sử dụng auto. Thật tầm thường khi thấy những gì hoạt động xhỗ trợ từ bối cảnh. Trong thực tế, loại này cung cấp cho bạn không có thông tin bổ sung: trong cả hai trường hợp bạn cần một số thứ cấp (IDE, tài liệu, kiến ​​thức / bộ nhớ) để cho bạn biết tập hợp các hoạt động được hỗ trợ.
Konrad Rudolph

1
@Ptolemy Đó là chỉ đúng nếu bạn đang ở trong tình hình phức tạp cao mà bạn không biết những gì beginlợi nhuận nhưng bạn làm biết những gì std::vector<>::iteratorlà. Và bạn cần sử dụng một công cụ lập trình tồi không thể cung cấp cho bạn thông tin này một cách tầm thường. Điều này là rất phức tạp. Trong thực tế, bạn có biết cả hai beginiteratorhay không, và bạn nên sử dụng một IDE hoặc biên tập viên có thể dễ dàng làm cho các thông tin có liên quan có sẵn cho bạn. Mỗi IDE hiện đại và biên tập lập trình có thể làm điều đó.
Konrad Rudolph

11

CHUYÊN NGHIỆP

Ma cua ban :

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

sẽ không biên dịch, vì tên phụ thuộc mẫu.

Đây là cú pháp đúng:

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

Bây giờ hãy xem khai báo kiểu là bao lâu. Điều này cho biết tại sao autotừ khóa được giới thiệu. Điều này :

for( auto it = x.begin(); it != x.end(); i++)

ngắn gọn hơn Vì vậy, đây là một pro.


CON

Bạn phải cẩn thận một chút. Với từ khóa auto, bạn có được loại bạn đã khai báo.

Ví dụ :

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

đấu với

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

Để kết luận: có, bạn nên, nhưng không lạm dụng nó. Một số người có xu hướng sử dụng nó quá nhiều và đặt tự động ở mọi nơi, như trong ví dụ tiếp theo:

auto i = 0;

đấu với

int i = 0;

auto i = 0. Tội lỗi. Tôi làm điều đó Nhưng đó là bởi vì tôi biết đó 0là một loại chữ int. (và hằng số bát phân ;-))
Laurent LA RIZZA

6

CÓ, bạn nên! autokhông xóa các loại; ngay cả khi bạn "không biết" x.begin()là gì , trình biên dịch sẽ biết và sẽ báo lỗi nếu bạn cố sử dụng sai loại. Ngoài ra, không phải là bất thường khi mô phỏng mapvới a vector<pair<Key,Value>>, vì vậy mã sử dụng autosẽ hoạt động cho cả hai biểu diễn từ điển.


4

Có, bạn nên sử dụng autonhư một quy tắc mặc định. Nó có lợi thế thô so với việc chỉ định rõ ràng loại:

  • Nó không làm cho bạn gõ những thứ mà trình biên dịch đã biết.
  • Nó làm cho loại biến "theo cùng" bất kỳ thay đổi nào trong các loại giá trị trả về.
  • Làm như vậy, nó ngăn chặn việc giới thiệu im lặng các chuyển đổi ngầm và cắt trong khởi tạo biến cục bộ.
  • Nó loại bỏ sự cần thiết của một số tính toán loại rõ ràng trong các mẫu.
  • Nó loại bỏ sự cần thiết phải đặt tên kiểu trả về với tên dài. (những cái bạn sao chép-dán từ chẩn đoán trình biên dịch)

Đây là nơi bạn có một sự lựa chọn. Cũng có trường hợp bạn không có lựa chọn:

  • Nó cho phép khai báo các biến của các loại không thể nhầm lẫn, như loại lambda.

Với điều kiện bạn biết chính xác những gì autonó làm, nó không có nhược điểm.

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.