2009-03-15 30 views
43

Bất cứ khi nào bạn phân bổ một mảng mới trong C# vớikhởi mảng trực tiếp với một giá trị không đổi

new T[length] 

các mục mảng được thiết lập để mặc định của T. Đó là null đối với trường hợp mà T là một loại tài liệu tham khảo hoặc kết quả của hàm tạo mặc định là T, nếu T là một loại giá trị.

Trong trường hợp của tôi, tôi muốn khởi tạo một mảng Int32 với giá trị -1:

var myArray = new int[100]; 
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; } 

Vì vậy, sau khi bộ nhớ được dành riêng cho mảng, CLR vòng qua bộ nhớ vừa được cấp phát và đặt tất cả các mục để mặc định (int) = 0. Sau đó, mã của tôi đặt tất cả các mục vào -1.

Điều đó làm cho việc khởi tạo không cần thiết. Liệu JIT có phát hiện ra điều này và bỏ qua việc khởi tạo đến 0 và nếu không, có cách nào để trực tiếp khởi tạo một phần bộ nhớ với một giá trị tùy chỉnh không?

Tham chiếu đến C# Array initialization - with non-default value, sử dụng Enumerable.Repeat(value, length).ToArray() không có tùy chọn, vì Enumerable.ToArray phân bổ mảng mới và sao chép các giá trị cho nó sau đó.

+1

Nếu bạn có byte mảng, sau đó [P/Invoke có thể giúp] (http://stackoverflow.com/a/19060558/380331). Nhưng nếu kích thước phần tử mảng lớn hơn byte (như trong trường hợp của bạn) - phương pháp này sẽ không hữu ích. –

Trả lời

32

Nó không thừa.

Giả sử một ngoại lệ được ném trong vòng lặp khởi tạo của bạn. Nếu CLR không xóa bộ nhớ trước, bạn có thể "nhìn thấy" bộ nhớ chưa được khởi tạo ban đầu, đó là một ý tưởng rất tồi, đặc biệt là từ quan điểm bảo mật. Đó là lý do tại sao CLR đảm bảo rằng bất kỳ bộ nhớ mới được cấp phát nào đều bị xóa sang mẫu 0 bit.

Cùng một đối số giữ cho các trường trong một đối tượng. Tôi giả sử trong cả hai trường hợp CLR có thể kiểm tra xem bạn sẽ không làm cho mảng hiển thị ở nơi khác trước khi hoàn thành khởi tạo hay không, nhưng đó là một kiểm tra phức tạp để tránh việc xóa vùng nhớ này một cách đơn giản ".

+0

Tôi không thấy nơi có thể ném ngoại lệ. JIT đủ thông minh để vô hiệu hóa các kiểm tra phạm vi trên mảng trong vòng lặp, vì vậy nó cũng có thể phát hiện ra rằng không có ngoại lệ nào có thể xảy ra. – Rauhotz

+6

@Rauhotz ThreadAbortException có thể được ném bất cứ lúc nào. – JaredPar

+0

OK, đó là một điểm – Rauhotz

3

Tôi rất nghi ngờ rằng JIT sẽ tối ưu hóa bộ mặc định cho trường hợp này. Lý do là vì đây sẽ là một sự khác biệt quan sát được. Hãy xem xét kịch bản hơi bị thay đổi sau đây.

obj.myArray = new int[100]; 
for (int i=0; i<myArray.Length; i++) { obj.myArray[i] = -1; } 

Hoàn toàn có thể cho vòng lặp ném. Ít nhất, nó có thể là không thể cho JIT để chứng minh nó không. Nếu nó đã ném và CLR không mặc định khởi tạo bộ nhớ, kết quả sẽ được quan sát nếu bạn vẫn có một tham chiếu đến obj.

+0

Hạn chế sự cố với biến cục bộ. – Rauhotz

+0

@Rauhotz, tại thời điểm đó bạn phải bắt đầu đặt câu hỏi liệu việc tối ưu hóa có đáng hay không. Bây giờ bạn đã giới hạn nó thành một kịch bản rất hạn chế. – JaredPar

10

Nếu bạn mua vào Arrays considered somewhat harmful, sau đó câu hỏi của bạn sẽ tranh luận như bạn sẽ viết:

var myArray = new List<int>(Enumerable.Repeat(-1, 100)); 
+4

Có lẽ đáng nói đến liên kết của anh ta là blog của Eric Lippert, điều này làm cho một trường hợp các mảng là tin xấu bởi vì trong nhiều trường hợp, "Người gọi đang yêu cầu các giá trị. Callee đáp ứng yêu cầu bằng cách chuyển các biến trở lại." Lippert lý thú cho rằng, do các ràng buộc vật lý tạo ra các bộ vi xử lý nhanh hơn, "Chúng ta sẽ cần các ngôn ngữ lập trình cho phép các con người chỉ viết mã song song với nhiều lõi [và mảng] ... mạnh mẽ chống lại mục tiêu này. " Đó là một đọc tuyệt vời, nếu hầu như không liên quan đến câu hỏi này. ; ^) – ruffin

26

Tương tự như câu trả lời của Dan nhưng không có nhu cầu sử dụng các bộ sưu tập:

int[] myArray = Enumerable.Repeat(-1, 100).ToArray(); 
Các vấn đề liên quan