2011-08-19 59 views
7

Có thể cung cấp danh sách trình khởi tạo cho định nghĩa của một mảng tĩnh. Ví dụ:Danh sách trình khởi tạo cho mảng động?

int main() 
{ 
    int int_static[2] = {1,2}; 
} 

Danh sách khởi tạo tương tự có thể cho mảng động không?

int main() 
{ 
    int* int_ptr = new int[2]; 
} 

Đây là gần gũi hơn với những gì tôi đang cố gắng để làm:

struct foo 
{ 
    foo(){} 
    foo(void * ptr): ptr_(ptr) {} 
    void * ptr_; 
}; 

int main() 
{ 
    foo* foo_ptr = new foo[10]; 
} 

Lúc khởi không phải là constructor mặc định nên được gọi, nhưng foo: foo (void *).

Điểm có danh sách khởi tạo tĩnh cho mảng động có thể hữu ích trong trường hợp biên dịch Just-In-Time cho lõi gia tốc chỉ có số lượng giới hạn stack, nhưng đồng thời bạn xây dựng đối tượng của bạn với một (thời gian biên dịch gia tốc = thời gian chạy máy chủ) danh sách khởi tạo tĩnh.

Tôi giả sử không (vì điều này sẽ yêu cầu trình biên dịch tạo mã bổ sung, cụ thể là sao chép các giá trị của đối số vào vị trí heap). Tôi nghĩ rằng c + + 0x hỗ trợ một số điều này, nhưng tôi không thể sử dụng nó. Ngay bây giờ tôi có thể sử dụng một cấu trúc như vậy. Có thể ai đó biết một thủ thuật ..

Tốt nhất!

Trả lời

9

Không, bạn không thể làm điều đó.

Tôi nghĩ C++ không cho phép điều này bởi vì cho phép điều đó không thêm bất kỳ tính năng nào của tính năng đẹp để có vào ngôn ngữ. Nói cách khác, điểm của mảng động là gì nếu bạn sử dụng bộ khởi tạo tĩnh để khởi tạo nó?

Mấu chốt của mảng động là tạo ra một mảng có kích thước N đó là biết khi chạy, tùy thuộc vào nhu cầu thực tế.Đó là, mã

int *p = new int[2]; 

làm cho ít ý nghĩa với tôi hơn như sau:

int *p = new int[N]; //N is known at runtime 

Nếu là như vậy, thì làm sao có thể giúp bạn cung cấp số phần tử trong tĩnh initializer vì N không được biết cho đến khi chạy?

phép giả định rằng bạn được phép viết này:

int *p = new int[2] {10,20}; //pretend this! 

Nhưng lợi thế lớn bạn đang nhận được bằng cách viết này? Không có gì. của nó gần như giống như:

int a[] = {10,20}; 

Ưu điểm thực sẽ là khi bạn được phép viết rằng đối với mảng của N yếu tố. Nhưng sau đó vấn đề là:

int *p = new int[N] {10,20, ... /*Oops, no idea how far we can go? N is not known!*/ }; 
+4

Đối với bản ghi, "động" không có nghĩa là "độ dài biến". Nó thực sự là một "tính năng tốt đẹp để có" để có thể tạo một đối tượng động mới và khởi tạo nó thành các nội dung ban đầu đã biết. Đó chính xác là những gì các nhà xây dựng làm cho các đối tượng kiểu lớp và cấu trúc. –

+0

Để làm rõ, 'động' trong C++ có nghĩa là phân bổ trên heap thay vì ngăn xếp. Tôi sử dụng cả hai bộ nhớ lưu trữ rộng rãi, do đó, có danh sách initializer làm việc cho cả hai sẽ cực kỳ thuận tiện. Như là, trong nhiều trường hợp khi tôi muốn tạo một danh sách mảng trên heap, tôi phải dùng đến các đối tượng (như std :: vector) thay vì các mảng đơn giản vì, như @MikeHousky nói, C++ chỉ hỗ trợ khởi tạo các đối tượng trên heap tại thời điểm này, không phải mảng. Không có vấn đề về kỹ thuật hoặc hiệu suất ở đây - chỉ là giới hạn của C++. – holocronweaver

0

Dữ liệu khởi tạo phải ở đâu đó. Đơn giản chỉ cần đặt tên nó.

Ví dụ:

#include <stddef.h> 
#include <algorithm>  // std::copy 
#include <vector> 

typedef ptrdiff_t Size; 

template< class Type, Size n > 
Size countOf(Type (&)[n]) { return n; } 

int main() 
{ 
    using namespace std; 

    static int const initData[] = {1,2}; 
    static Size const n   = countOf(initData); 

    // Initialization of a dynamically allocated array: 
    int*  pArray = new int[n]; 
    copy(initData, initData + n, pArray); 

    // Initialization of a vector: 
    vector<int> v(initData, initData + n); 
} 

EDIT: cố định một thinko trong mã ở trên. Tôi đã vội vã thêm ví dụ theo yêu cầu. Vì vậy, những gì tôi đặt đã sử dụng sai giá trị trả lại từ std::copy.

Cheers & h.,

+0

Điều này không rõ ràng. Bạn có thể đưa ra một ví dụ minh họa? –

+0

@Oli, tôi đoán anh ta đề cập đến một cái gì đó tương tự như giải pháp mà tôi đề xuất trong câu trả lời của tôi, chỉ cần bỏ qua các chi tiết đẫm máu của bản sao cần thiết. –

+0

OK, xong.Tôi không hiểu những gì chưa rõ ràng. –

2

Không, bạn sẽ phải tạo ra các yếu tố động.

Ngoài ra, bạn có thể sử dụng một mảng cục bộ và sao chép phần tử của nó trên những mảng cấp phát động:

int main() { 
    int _detail[] = { 1, 2 }; 
    int * ptr = new int[2]; 
    std::copy(_detail, _detail+(sizeof detail/sizeof *detail), ptr); 
    delete [] ptr; 
} 

Trong phiên bản hạn chế về thiết lập tất cả các yếu tố để 0, bạn có thể sử dụng thêm một cặp ngoặc trong số gọi new:

int * ptr = new int[2](); // will value initialize all elements 

Nhưng dường như bạn đang tìm kiếm một thứ khác.

+0

Dấu chấm câu trong câu đầu tiên của bạn hơi gây hiểu nhầm; đã "cố định". Rollback nếu bạn không đồng ý. –

+0

Tôi đang tìm kiếm chính xác một cách để gọi hàm tạo của mỗi phần tử được phân bổ động (tất nhiên nó không chỉ là một "int"). Nhưng nó không phải là nhà xây dựng tiêu chuẩn mà phải được gọi. Nó phải mất 1 arg và lvalue cho đối số đó là cho mỗi phần tử khác nhau. – ritter

+0

không nên _detail là một int *? –

0

Vì bạn là lớp thực sự phức tạp hơn một int và được xây dựng từ các giá trị khác nhau, nó phức tạp. Một vectơ có thể được xây dựng với các trình vòng lặp nếu bạn có một mảng/vectơ hiện có với các giá trị chính xác để mặc định từ, hoặc bạn phải sử dụng vị trí mới.

//vector 
int main() 
{ 
    int int_static[2] = {1,2}; 
    std::vector<int> int_dynamic(int_static, int_static+2); 
    //this is what everyone else is saying. For good reason. 
} 
//placement new 
int function_that_returns_constructed_from_values() { 
    return rand(); 
} 
int main() 
{ 
    int count = 2; 
    char *char_dynamic = new char[count * sizeof(int)]; 
    int *int_dynamic = char_dynamic; 
    for(int i=0; i<count; ++i) 
     new(int_dynamic+i)int(function_that_returns_constructed_from_values()); 
    //stuff 
    for(int i=0; i<count; ++i) 
     (int_dynamic+i)->~int(); //obviously not really int 
    delete []char_dynamic; 
} 

Rõ ràng, vector là cách ưu tiên để thực hiện việc này.

10

Vào thời điểm OP đăng câu hỏi này, hỗ trợ C++ 11 có thể chưa được phổ biến lắm, đó là lý do tại sao câu trả lời được chấp nhận cho biết điều này là không thể. Tuy nhiên, việc khởi tạo một mảng động với một danh sách khởi tạo rõ ràng bây giờ sẽ được hỗ trợ trong tất cả các trình biên dịch C++ chính.

Cú pháp new int[3] {1, 2, 3} được chuẩn hóa trong C++ 11. Trích dẫn trang new expression trên cppreference.com:

Đối tượng được tạo ra bởi một mới thể hiện được khởi tạo theo các quy tắc sau:
...
Nếu loại là một loại mảng, một mảng đối tượng được khởi tạo:
...
Nếu initializer là danh sách các đối số được bao bọc bằng ngoặc kép, mảng được tổng hợp khởi tạo. (Vì C++ 11)

Vì vậy, được đưa ra ví dụ của OP, sau đây là hoàn toàn hợp pháp khi sử dụng C++ 11 hoặc mới hơn:

foo * foo_array = new foo[2] { nullptr, nullptr }; 

Lưu ý rằng bằng cách cung cấp con trỏ trong danh sách initializer , chúng tôi đang thực sự đồng bộ hóa trình biên dịch để áp dụng hàm tạo foo(void * ptr) (thay vì hàm tạo mặc định), đó là hành vi mong muốn.

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