2012-06-29 50 views
14

Vâng, tôi không nghĩ rằng nó thực sự quan trọng nhưng vì chương trình phải lưu trữ độ dài vì xóa [] anyway, Tại sao chúng ta không thể có được "thông tin được lưu trữ" này?C++ tại sao không có cái gì đó như chiều dài (mảng)?

+6

Bởi vì đó là những gì tiêu chuẩn C++ nói. –

+1

Không phải là một câu hỏi thực sự, bạn có mã mà bạn có câu hỏi không? – trumpetlicks

+2

@trumpetlicks tại sao không? Tôi xem nó như một câu hỏi về một tính năng ngôn ngữ. Nó có thể hữu ích để biết động cơ. –

Trả lời

9

Việc triển khai chỉ cần lưu trữ độ dài và thường chỉ thực hiện, nếu loại không bị phá hủy tầm thường (nghĩa là cần tạo cuộc gọi đến trình phá hủy) và mảng được tạo bằng toán tử [] mới.

Vì thuộc tính của loại được sắp xếp không có liên quan đến kích thước của mảng nên thanh lịch đơn giản hơn là gọi chiều dài "cookie" là chi tiết triển khai riêng tư.

Để nhận độ dài của đối tượng mảng hoàn chỉnh (không phải là con trỏ đơn thuần), bạn có thể sử dụng std::extent< decltype(arr) >::value hoặc std::end(arr) - std::begin(arr).

Sử dụng new[] với lớp có hàm hủy là một mã có mùi. Thay vào đó, hãy xem xét std::vector. Chi phí trên so với số liệu thô new[] (xem xét tất cả các byte cần phân bổ, bất kể chúng ở đâu) là giá trị byte của một con trỏ và lợi ích là vô số.

+0

Thêm vào đó không khó để có được độ dài với những gì ngôn ngữ cung cấp, ví dụ: với việc triển khai mẫu chuẩn. –

+1

Trên thực tế, chi phí của 'vector' là hai con trỏ (hoặc kích thước), vì nó phải theo dõi cả kích thước và dung lượng. +1 anyway. –

+0

@MikeSeymour Nhưng trừ một con trỏ trên đầu vì cookie 'length' của mảng động lớn bằng con trỏ. – Potatoswatter

0

vì việc triển khai nơi lưu trữ thông tin này. do đó không có cách chung để thực hiện chiều dài (mảng)

+8

'chiều dài (mảng)' cũng có thể được thực hiện. – Kos

1

Không phải tất cả các mảng được phân bổ bởi new.

void f(int* arr, size_t n) 
{ 
    length(arr); // ??? 
} 


int main() 
{ 
    int a[5]; 
    f(a); 
} 

Đó là tầm thường để viết mặc dù, chỉ cần gọi (std::end(arr) - std::begin(arr)), mặc dù nó chỉ có tác dụng đối với mảng, không phải con trỏ trỏ tới đầu mảng.

+0

Bí quyết '(sizeof (arr)/sizeof (* arr)) cũ cũng hoạt động cho các mảng thực, nhưng tôi thích kiểu mới – stefaanv

+0

Phép trừ Iterator không thể (dễ dàng) được tối ưu hóa thành hằng số. sizeof là, nhưng nó kém an toàn hơn. 'template constexpr std :: size_t length (T (&) [N]) {return N; } 'là an toàn và có thể tối ưu hóa thành hằng số. –

+0

@JoeWreschnig, những người không phải là vòng lặp chung, chúng là con trỏ và sự khác biệt giữa hai địa chỉ trong cùng một mảng có thể được tối ưu hóa thành hằng số. Và tôi đề nghị 'kết thúc' bởi vì đó là tầm thường, trong khi xác định rằng mẫu hàm không quan trọng, nó liên quan đến các tham số mẫu không phải kiểu và khai báo mảng xấu - không thích hợp cho người mới bắt đầu! –

2

Hãy xem xét các trường hợp:

char* a = new char[100]; 

Bây giờ a nhu cầu để trỏ đến một bộ đệm đó là ít nhất 100 ký tự lớn, nhưng hệ thống có thể phân bổ một bộ đệm lớn hơn để đáp ứng này. Với điều này trong tâm trí, chúng ta có thể thấy rằng hệ thống là miễn phí để ngay lập tức quên kích thước chương trình yêu cầu, miễn là nó vẫn có thể deallocate bộ đệm đúng sau này. Quay lại đầu trang | (Hoặc bằng cách nhớ kích thước của bộ đệm được phân bổ hoặc thực hiện cấp phát bộ nhớ với một số cấu trúc dữ liệu thông minh mà chỉ cần con trỏ đến bắt đầu)

Vì vậy, trong trường hợp chung, thông tin bạn đang tìm kiếm là không, trên thực tế, được lưu trữ ở mọi nơi.

0

Độ dài chắc chắn không được lưu trữ trên tất cả các triển khai. Ví dụ, C++ cho phép thu gom rác thải (ví dụ: boehmgc) và nhiều người thu thập không cần biết chiều dài. Trong phân bổ truyền thống, độ dài được lưu trữ thường sẽ lớn hơn chiều dài thực tế, tức là độ dài được phân bổ, không phải độ dài được sử dụng.

+2

Độ dài (số lượng đối tượng, không phải byte) cần phải được lưu trữ ở đâu đó nếu các đối tượng của mảng có các destructial không độc hại. Một cơ chế như vậy là minh bạch cho trình phân bổ, mà phân bổ một cách mù quáng một số byte đệm để thực hiện. GC với các đối tượng không phải POD là một tính năng mới và xuất hiện. – Potatoswatter

+0

vâng, nhưng đó chỉ là một tập hợp con các trường hợp, và tôi có thể nghĩ ra cách để tránh lưu trữ độ dài (ví dụ: các khóa bí mật.) –

+0

Không chắc chắn ý bạn là gì. Bạn có ý định sử dụng byte đệm cho sentinel không? Điều gì xảy ra nếu không có đệm? Dù sao, tất cả các triển khai thực hiện nó theo cùng một cách, do đó, "không được lưu trữ trên tất cả các triển khai" là sai ... mặc dù nó cũng đúng là có trường hợp không thực hiện lưu trữ một giá trị độ dài. Xem câu trả lời của tôi. – Potatoswatter

0

Nhưng chính xác chiều dài của mảng là bao nhiêu? Có phải số byte trong mảng hoặc số phần tử trong mảng không?

Ví dụ: đối với một số loại A có kích thước 100 byte,

A * myArray = new A [100];

nên dài (myArray) trả về 100 hoặc 100 * 100? Ai đó có thể muốn 100, ai đó có thể muốn 10000.Vì vậy, không có lập luận thực sự cho một trong số đó.

+1

C++ luôn ưu tiên đối tượng đếm chứ không phải byte. – Potatoswatter

1

Sự hiểu biết của tôi là triết lý của C++ là không ép buộc mọi người bất kỳ tính năng nào có chi phí tiềm năng trừ khi không thể tránh khỏi.

Có thể có thêm chi phí để lưu trữ thông tin này và người dùng có thể không muốn thanh toán chi phí đó nếu họ không cần thông tin. Và vì nó tầm thường để lưu trữ độ dài chính mình nếu bạn muốn nó không có lý do để cung cấp một tính năng ngôn ngữ mà có một chi phí cho tất cả mọi người bằng cách sử dụng một mảng.

1

Đối thích mảng, có nghĩa là, int a[length], bạn đã có cơ sở rằng: chỉ cần làm

#define length(A) (sizeof(A)/sizeof(*A)) 

và bạn đang thực hiện với nó.

Nếu bạn đang nói về độ dài của mảng được trỏ tới bởi con trỏ, thì, con trỏ và mảng là hai khái niệm khác nhau và ghép chúng không có ý nghĩa, ngay cả khi các mảng thích hợp "phân rã" thành con trỏ khi cần thiết và bạn truy cập mảng thông qua số học con trỏ. Tuy nhiên, ngay cả khi chúng tôi không tính đến điều đó và nói về khía cạnh công nghệ, thời gian chạy của C++ có thể không biết chiều dài của mảng của bạn là gì, vì new có thể dựa trên malloc, lưu trữ độ dài của mảng trong các cách cụ thể của nó, chỉ được hiểu bởi free: thời gian chạy C++ chỉ lưu trữ thông tin bổ sung khi bạn có các trình phá hủy không trống. Một bức tranh khá lộn xộn, huh?

+0

Bạn cũng có thể sử dụng giá trị std :: extent ::. – bstamour

+0

điều cần biết, cảm ơn – akappa

0

Các C++ kiểu đó hoạt động hầu như "mảng" trong ngôn ngữ có hỗ trợ length(array)std::vector<>, và nó khôngstd::vector<>::size().

Kích thước của đồng bằng [] mảng được biết là trình biên dịch trong phạm vi nơi có kích thước là rõ ràng, tất nhiên, nhưng nó có thể để vượt qua họ để phạm vi nơi có kích thước là không biết trình biên dịch. Điều này mang lại cho C++ nhiều hơn các cách xử lý dữ liệu giống như mảng so với các ngôn ngữ phải hỗ trợ một liên kết length (vì chúng phải đảm bảo rằng kích thước luôn được chuyển).

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