2012-11-13 66 views
9

Khi tôi làm một cái gì đó như thế này:Làm thế nào để C++ 11 dựa trên phạm vi cho vòng lặp biết kích thước mảng?

int my_array[5] = {1, 2, 3, 4, 5}; 
for (int &x : my_array) { 
    x *= 2; 
} 

C++ 11 rõ ràng biết rằng mảng của tôi chỉ có 5 yếu tố. Thông tin này có được lưu trữ ở đâu đó trong đối tượng my_array không?

Nếu có, có lý do chính đáng nào tại sao nó không được cung cấp cho tôi với tư cách là nhà phát triển (hay là nó?!?!?)? Có vẻ như rất nhiều vấn đề của thế giới sẽ được giải quyết nếu các nhà phát triển C++ luôn biết giới hạn của các mảng mà họ đang xử lý.

Trả lời

11

Đây đơn giản là thứ mà ngôn ngữ yêu cầu phải hoạt động và trình biên dịch phải triển khai. Rõ ràng là loại hoàn chỉnh của my_arrayint[5] (nghĩa là kích thước là một phần của loại), vì vậy thông tin này có sẵn.

Trái ngược với niềm tin phổ biến, có không sử dụng miễn phí std::begin()/std::end() chức năng trong vở kịch, mặc dù những người có vẻ ngây thơ để có thể làm các trick (nhưng có một bắt liên quan đến ADL rằng sẽ phá vỡ phương pháp này) .

+0

Ok. Vì vậy, có bất kỳ lý do cụ thể tại sao một my_array.size không tồn tại? – MrFox

+6

@suslik: Chắc chắn, vì mảng không phải là loại lớp và do đó không thể có các hàm thành viên. Nhưng bạn có thể viết một cách tự nhiên một mẫu hàm miễn phí 'array_size' để tạo ra giá trị mong muốn, hoặc sử dụng [' std :: extent'] được tạo sẵn (http://en.cppreference.com/w/cpp/types/extent). –

+0

Làm thế nào tôi sống cuộc sống của tôi không biết về điều này quá lâu ... Tôi đổ lỗi cho std :: vector :). – MrFox

5

Không, nó không phải là một phần của đối tượng. Nhưng đó là một phần của loại. Đó là những gì mà 5 trong khai báo mảng là. Tuy nhiên, điều này sẽ không làm việc:

void f(int arr[5]) { 
    for(int& x: arr) { 
     // whatever 
    } 
} 

vì tên của mảng ở đây phân rã thành một con trỏ đến phần tử đầu tiên của mình, đó là, việc khai báo đối số là tương đương với int *arr mà không có thông tin kích thước.

+3

Tôi sẽ không sử dụng thuật ngữ 'phân rã' trong trường hợp này. Tôi nghĩ rằng thuật ngữ này thường là cụ thể cho việc chuyển đổi ngầm được thực hiện thành một biến mảng trong nhiều biểu thức. 'int a [5]; a + 1; // decay' Thay vào đó tôi muốn đề cập đến những gì xảy ra ở đây với thuật ngữ 'điều chỉnh' vì đó là từ mà tiêu chuẩn sử dụng. 'void foo (int a [5]); // type 'adjustment': tương đương với void foo (int * a) '. Và tôi thích sử dụng một giọng mỉa mai khi tôi nói từ đó. – bames53

+0

Điều này sẽ làm việc mặc dù. 'void f (int (& arr) [5]) {...}' – balki

+0

Để tham khảo, giải pháp @ balki không hoạt động với các tham chiếu mảng chưa được phân loại, ví dụ: '(& arr) [5]'. Nhưng nó thường có thể được thực hiện để làm việc cho các mảng có kích thước chung bằng cách sử dụng kích thước mảng làm tham số mẫu: xem https://stackoverflow.com/questions/26182907/range-based-for-loop-on-array-passed- không chính-chức năng – andybuckley

6

Có sẵn - bạn có thể xác định beginend trên mảng trong tiêu chuẩn C++. Kích thước của mảng được mã hóa trong loại.

Phương pháp chung là sử dụng tham chiếu đến mảng.

Dưới đây là một chức năng ví dụ kích thước:

template<typename T, size_t N> 
size_t array_size(T (& const)[N]) 
{ 
    return N; 
} 
+6

Điều này còn được gọi là 'std :: extent'.Và 'std :: begin' và' std :: end' là * đã * định nghĩa cho các mảng trong thư viện chuẩn. –

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