2012-03-17 49 views
6

Tôi đang viết một hạt nhân nhỏ với C++ 11 và có hai cá thể cùng loại mà phải được tạo trước khi bất kỳ đối tượng tĩnh nào khác được tạo.Kiểm soát thứ tự của hàm tạo đối tượng tĩnh

Mã tôi đã viết như sau:

// test.hpp 
class test { 
    // blahblah... 
}; 

// test.cpp 
typedef char fake_inst[sizeof(test)] __attribute__((aligned(alignof(test)))); 

fake_inst inst1; 
fake_inst inst2; 

// main.cpp 
extern test inst1; 
extern test inst2; 

int kmain() { 
    // copy data section 

    // initialize bss section 

    new (&inst1) test(); 
    new (&inst2) test(); 

    // call constructors in .init_array 

    // kernel stuffs 
} 

Nó xây dựng và các công trình như mong đợi mà không có tin nhắn cảnh báo, nhưng không phải với LTO.

Tôi nhận được rất nhiều thông báo cảnh báo phàn nàn về loại đối sánh và tôi tự hỏi liệu có giải pháp nào không vì nó làm tôi bối rối khi tìm thấy thông báo lỗi hoặc cảnh báo 'thực' khác.

Bất kỳ đề xuất nào?

+0

Bạn đang * thực sự * đang cố gắng làm gì? Trong phần bình luận của Pubby dưới đây bạn nói rằng bạn muốn khởi tạo một vài đối tượng cùng loại. Với tôi, có vẻ như bạn muốn khởi tạo các cấu trúc liên quan đến hỗ trợ C++, chẳng hạn như vùng heap, trước khi cho phép thực hiện gọi các nhà xây dựng khác. Nhưng điều đó không giống như những gì bạn đang cố gắng. Ngoài ra, bạn sẽ nhận được cảnh báo loại "loại đối sánh" nào? – Potatoswatter

+0

@Potatoswatter rất nhiều cảnh báo: loại ‘xxx’ không khớp với khai báo ban đầu [được bật theo mặc định] 'mọi thứ. Đó là vì loại thực tế không phải là thử nghiệm nhưng char []. Tôi nghĩ rằng tôi có thể vô hiệu hóa constructor tĩnh nhưng dường như không có cách nào để làm điều đó. – kukyakya

+0

Ah, tôi hiểu rồi. Những gì bạn nên làm là 'char fake_inst1 [sizeof (test)]; test * const inst1 = reinterpet_cast < test * > (fake_inst1); ' – Potatoswatter

Trả lời

0

Có lẽ như thế này?

// ... .h 
template<typename T> 
union FakeUnion { 
    FakeUnion() {} 
    ~FakeUnion() {} 

    T inst; 
}; 

extern FakeUnion<test> inst1_; 
extern FakeUnion<test> inst2_; 
static constexpr test& inst1 = inst1_.inst; 
static constexpr test& inst2 = inst2_.inst; 
// ... .h end 

// ... .cpp 
FakeUnion<test> inst1_; 
FakeUnion<test> inst2_; 
// ... .cpp end 

Trong vòng main, sau đó bạn có thể nói new (&inst1) test;. Nó không nên đưa ra cảnh báo về loại vi phạm không nhất quán nữa bây giờ, bởi vì không giống như trong mã của bạn, mã này không chứa các biến có các loại khác nhau trong các tệp khác nhau.

+0

Trong khi điều này giải quyết được xung đột tên, nó không đảm bảo rằng hàm tạo của 'inst1' và' inst2' được gọi trước bất kỳ khác. –

+0

@Matt nếu anh ta gọi chúng trong 'main' với vị trí mới, nó đảm bảo như vậy nếu tất cả các ctors khác được gọi sau khi' main' một cách có kiểm soát. –

+0

Bạn có thể tư vấn về "ma thuật" xảy ra ở đây không? I E. tại sao chúng ta cần một công đoàn và tại sao công đoàn lại có ctor/dtor? – Farcaller

1

Bạn có thể sử dụng thuộc tính init_priority của GCC không?

Some_Class A __attribute__ ((init_priority (2000))); 
Some_Class B __attribute__ ((init_priority (543))); 

http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#C_002b_002b-Attributes

+0

Tôi đã đọc về điều đó nhưng thật khó để quản lý thứ tự của các nhà xây dựng vì những thứ ưu tiên được lan truyền trên các tệp nguồn. – kukyakya

+0

@kukyakya do đó vấn đề là khởi tạo hai đối tượng đầu tiên, hoặc đặt hàng tất cả các nhà thầu toàn cầu nói chung? – Potatoswatter

+0

@Potatoswatter Trên thực tế nó không chỉ là hai trường hợp, nhưng nhiều hơn một trường hợp cho cùng một loại, vì vậy tôi không thể sử dụng mẫu đơn. Thứ tự xây dựng của các đối tượng tĩnh khác không quan trọng. – kukyakya

0
// in an .h file 

typedef char fake_inst[sizeof(test)] __attribute__((aligned(__alignof__(test)))); 

extern fake_inst fake_inst1; 
extern fake_inst fake_inst2; 

inline test& f_inst1() { return *reinterpret_cast<test*>(fake_inst1); } 
inline test& f_inst2() { return *reinterpret_cast<test*>(fake_inst2); } 

// and for readability 

static test& inst1 (f_inst1()); 
static test& inst2 (f_inst2()); 

Hy vọng rằng cả hai inst1f_inst1() sẽ được tối ưu hóa ra.

+0

Đây chính xác là cách tôi đang sử dụng, nhưng tôi tự hỏi nếu có một cách neater. Tôi muốn các đối tượng toàn cục như 'std :: cout' hoặc' std :: cin' vì nó có vẻ dễ đọc hơn hàm trả về. – kukyakya

+0

Xem phiên bản cập nhật. –

+0

có thể thử biến tham chiếu toàn cầu, được khởi tạo để khôi phục 'inst1'? Điều này cũng được tối ưu hóa (trong msvc) – valdo

2

C++ không cung cấp cho bạn các cách quản lý thứ tự khởi tạo cho các đối tượng chung trên nhiều tệp. Nếu bạn cần quản lý thứ tự khởi tạo của các đối tượng này một cách chặt chẽ, thì tôi khuyên bạn mạnh mẽ để không biến chúng thành các đối tượng toàn cầu. Đặt chúng thành các hàm toàn cục chứa các đối tượng tĩnh và trả về các con trỏ cho chúng.

Nhưng ngay cả khi đó, điều đó ít nguy hiểm hơn việc khởi chạy thủ công hoàn toàn. Chỉ cần thực hiện một vài gợi ý cho những đối tượng có sẵn cho những người cần chúng (tốt nhất là không phải trên toàn cầu), và bạn sẽ ổn thôi.

+0

Tôi đã xem xét việc sử dụng các hàm toàn cục trả về tham chiếu hoặc con trỏ tới các đối tượng tĩnh phạm vi chức năng nhưng trình biên dịch tạo ra các thứ có được/giải phóng để tạo cá thể và các phần tử lấy/giải phóng được thực hiện với kernel mutex, không thể được sử dụng trong kernel khởi tạo. – kukyakya

+0

@kukyakya: Sau đó, bạn sẽ phải khởi tạo các đối tượng này theo cách thủ công. Đó là cách duy nhất để chắc chắn không có mutexes kernel. –

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