C ++ auto & vs auto


88

Khi tạo các biến cục bộ, sử dụng có đúng (const) auto&hay autokhông?

ví dụ:

SomeClass object;
const auto result = object.SomeMethod();

hoặc là const auto& result = object.SomeMethod();

Trong đó SomeMethod () trả về một giá trị không phải nguyên thủy - có thể là một kiểu khác do người dùng xác định. Sự hiểu biết của tôi const auto& resultlà đúng vì kết quả trả về bởi SomeMethod () sẽ gọi hàm tạo bản sao cho kiểu được trả về. Xin vui lòng sửa cho tôi nếu tôi sai.

Còn đối với các loại nguyên thủy thì sao? Tôi cho const auto sum = 1 + 2;là đúng.

Điều này cũng áp dụng cho phạm vi dựa trên vòng lặp?

for(const auto& object : objects)

1
Tôi thực sự khuyên bạn nên đọc cái này: safaribooksonline.com/library/view/effective-modern-c/… Hai chương đầu là miễn phí và mô tả loại trừ mẫu, về cơ bản là cách autohoạt động (ngoại trừ trường hợp đặc biệt của initializer_lists, là không được suy luận trong ngữ cảnh mẫu), sau đó autonhập suy luận.
vsoftco

Câu trả lời:


102

autoauto &&bao gồm hầu hết các trường hợp:

  • Sử dụng autokhi bạn cần một bản sao cục bộ. Điều này sẽ không bao giờ tạo ra một tham chiếu. Hàm tạo bản sao (hoặc di chuyển) phải tồn tại, nhưng nó có thể không được gọi, do tối ưu hóa tách bản sao .

  • Sử dụng auto &&khi bạn không quan tâm đối tượng có phải là cục bộ hay không. Về mặt kỹ thuật, điều này sẽ luôn tạo ra một tham chiếu, nhưng nếu trình khởi tạo là tạm thời (ví dụ: hàm trả về theo giá trị), về cơ bản nó sẽ hoạt động giống như đối tượng cục bộ của riêng bạn.

    Ngoài ra, auto &&cũng không đảm bảo rằng đối tượng sẽ có thể sửa đổi được. Đưa ra một constđối tượng hoặc tham chiếu, nó sẽ suy ra const. Tuy nhiên, khả năng sửa đổi thường được giả định, với bối cảnh cụ thể.

auto &auto const &cụ thể hơn một chút:

  • auto &đảm bảo rằng bạn đang chia sẻ biến với thứ gì đó khác. Nó luôn luôn là một tham chiếu và không bao giờ là tạm thời.

  • auto const &giống như auto &&, nhưng cung cấp quyền truy cập chỉ đọc.

Còn đối với các kiểu nguyên thủy / không nguyên thủy thì sao?

Không có sự khác biệt.

Điều này cũng áp dụng cho phạm vi dựa trên vòng lặp?

Đúng. Áp dụng các nguyên tắc trên,

  • Sử dụng auto &&cho khả năng sửa đổi và loại bỏ các giá trị của chuỗi trong vòng lặp. (Nghĩa là, trừ khi vùng chứa cung cấp chế độ xem chỉ đọc, chẳng hạn như std::initializer_list, trong trường hợp đó, nó thực sự là một auto const &.)
  • Sử dụng auto &để sửa đổi các giá trị của chuỗi theo cách có ý nghĩa.
  • Sử dụng auto const &cho quyền truy cập chỉ đọc.
  • Sử dụng autođể làm việc với các bản sao (có thể sửa đổi).

Bạn cũng đề cập đến auto constmà không có tài liệu tham khảo. Điều này hoạt động, nhưng nó không được sử dụng phổ biến vì hiếm khi có lợi thế khi truy cập chỉ đọc vào thứ mà bạn đã sở hữu.


Sutter nói rằng tự động & theo dõi hằng số
Jesse Pepper

1
@JessePepper Có. (Tuy nhiên, hơi kỳ lạ khi khiếu nại với chính quyền.) Bạn đang đề cập đến một phần cụ thể của điều này?
Potatoswatter

Về bản chất auto&có vẻ là một lựa chọn tốt. Nhưng sử dụng const auto&khi bạn muốn thêm hằng số chưa có. auto&&là để chuyển tiếp, điều mà tôi nghĩ xảy ra thường xuyên hơn Sutter nghĩ. Ví dụ: bạn có thể muốn lưu trữ một giá trị trả về auto&&và sau đó "chuyển tiếp" nó đến hai thứ, như std :: cout để xem giá trị để gỡ lỗi và cũng chuyển nó cho một số hàm khác. Tôi đã từng sử dụng auto && thường xuyên hơn nhưng đã bị nó cắn một hoặc hai lần khi nó làm một số việc không mong muốn. Tôi ước tôi lưu ý nhiều hơn về những gì đã xảy ra!
Jesse Pepper

@JessePepper Vâng, auto&&có liên quan của một tính năng ngôn ngữ mất tích, mà nên cho phép bất kỳ tuyên bố được chia thành các báo cáo nhỏ hơn. Phần còn thiếu là gia hạn thời gian tồn tại… Tôi đã nỗ lực khá nhiều để sửa lỗi này nhưng không ai nhận ra. Đừng đặt quá nhiều chứng khoán trong punditry :)
Potatoswatter

Trên auto const: Có thể tự nhiên hơn khi viết auto const x = fn (); nếu bạn biết hàm không trả về tham chiếu và bạn muốn đối tượng x không thay đổi, để tránh lỗi hoặc ghi lại nó được sử dụng trong phạm vi. Theo cách tương tự mà bạn thường không viết: const int & x = 1; Nhưng auto const & does cho kết quả tương đương do các quy tắc mở rộng trọn đời cho các tham chiếu được khai báo theo cách này.
Spacen Jasset

47

Có, sử dụng autoauto&cho các biến cục bộ là đúng . Khi nhận được kiểu trả về của một hàm, nó cũng đúng để sử dụng auto&. Điều này cũng áp dụng cho phạm vi dựa trên vòng lặp.

Các quy tắc chung để sử dụng autolà:

  • Chọn auto xthời điểm bạn muốn làm việc với các bản sao.
  • Chọn auto &xthời điểm bạn muốn làm việc với các mục gốc và có thể sửa đổi chúng.
  • Chọn auto const &xthời điểm bạn muốn làm việc với các mục gốc và sẽ không sửa đổi chúng.

Bạn có thể đọc thêm về thông số tự động tại đây .


9

autosử dụng cùng cơ chế loại trừ như mẫu, ngoại lệ duy nhất mà tôi biết được rằng các danh sách cú đúp-init, được suy luận bởi autonhư std::initializer_list, nhưng không suy luận trong một mẫu ngữ cảnh.

auto x = expression;

hoạt động bằng cách trước tiên loại bỏ tất cả các định nghĩa tham chiếu và cv khỏi loại biểu thức bên phải, sau đó khớp với loại. Ví dụ, nếu bạn có const int& f(){...}rồi auto x = f();suy luận xnhư int, và không const int& .

Các hình thức khác,

auto& x = expression

không loại bỏ các định tính cv, do đó, sử dụng ví dụ trên, auto& x = f()suy ra xconst int&. Các kết hợp khác chỉ thêm vòng loại cv.

Nếu bạn muốn kiểu của mình luôn được suy ra với các định tính cv-ref, hãy sử dụng kiểu khét tiếng decltype(auto)trong C ++ 14, sử dụng các decltypequy tắc trừ kiểu.

Vì vậy, tóm lại, nếu bạn muốn bản sao, hãy sử dụng auto, nếu bạn muốn tài liệu tham khảo, hãy sử dụng auto&. Sử dụng constbất cứ khi nào bạn muốn bổ sung const-ness.


CHỈNH SỬA Có một trường hợp sử dụng bổ sung,

auto&& x = expression;

sử dụng quy tắc thu gọn tham chiếu, giống như trong trường hợp chuyển tiếp tham chiếu trong mã mẫu. Nếu expressionlà một lvalue, thì đó xlà một tham chiếu giá trị với các định tính cv của expression. Nếu expressionlà một rvalue, thì đó xlà một tham chiếu rvalue.


@Potatoswatter Cảm ơn, đã chỉnh sửa. Tôi thực sự thắc mắc về cv cho rvalues. Có cách nào đơn giản để kiểm tra không? Và làm thế nào bạn có thể có một rvalue đủ tiêu chuẩn cv? Trên hàm trả về cv bị loại bỏ.
vsoftco

Không, nó không bị loại bỏ khi trả về hàm. Nó bị loại bỏ đối với các giá trị pr của tất cả các kiểu vô hướng (C ++ 14 [và các phiên bản khác] §5 / 6). Bạn có thể lấy một hàm bằng lệnh gọi hàm hoặc ký hiệu ép kiểu. Các xvalue đủ tiêu chuẩn cv hoạt động giống như bất kỳ thứ gì khác: auto && x = std::move< const int >( 5 );sẽ khai báo int const && x, mặc dù chúng hiếm khi được sử dụng.
Potatoswatter

@Potatoswatter cảm ơn, bạn nói đúng, lỗi của tôi. Tôi đã thử nghiệm đầu tiên với POD, trong trường hợp đó cv bị loại bỏ và nghĩ rằng đó là trường hợp chung. Tất nhiên nó không nên bị loại bỏ, vì nói chung người ta có thể muốn giữ lại cv (ví dụ như vậy người ta không thể gọi hàm thành viên không phải const trên trả về rvalue).
vsoftco

Bị loại bỏ đối với các loại vô hướng. POD có thể là các lớp. Dù sao, đó cũng là một góc khuất của giao điểm giữa mô hình biểu thức và mô hình đối tượng.
Potatoswatter

2

Khi tạo biến cục bộ, sử dụng (const) auto & hoặc auto có đúng không?

Đúng. Tự động không có gì khác hơn là một kiểu do trình biên dịch suy ra, vì vậy hãy sử dụng các tham chiếu mà bạn thường sử dụng tham chiếu và các bản sao cục bộ (tự động) nơi bạn thường sử dụng các bản sao cục bộ. Việc sử dụng tham chiếu có phụ thuộc vào kiểu suy diễn hay không.

Trong đó SomeMethod () trả về một giá trị không phải nguyên thủy - có thể là một kiểu khác do người dùng xác định. Sự hiểu biết của tôi là const auto & result là đúng vì kết quả được trả về bởi SomeMethod () sẽ gọi hàm tạo bản sao cho kiểu trả về. Xin vui lòng sửa cho tôi nếu tôi sai.

Hợp pháp? Có, với hằng số. Thực hành tốt nhất? Có lẽ không, không. Ít nhất, với C ++ 11 thì không. Đặc biệt là không, nếu giá trị trả về từ SomeMethod () đã là tạm thời. Bạn sẽ muốn tìm hiểu về ngữ nghĩa di chuyển C ++ 11, sao chép elision và tối ưu hóa giá trị trả về: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- giá trị/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

Còn đối với các loại nguyên thủy thì sao? Tôi giả sử const auto sum = 1 + 2; đúng.

Vâng, điều này là tốt.

Điều này cũng áp dụng cho phạm vi dựa trên vòng lặp?

for (const auto & object: objects)

Vâng, điều này cũng tốt. Tôi viết loại mã này tại nơi làm việc mọi lúc.

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.