2012-02-01 47 views
5

Tôi đang biên soạn một thư viện được chia sẻ với hai đơn vị biên dịch: globals.cppstuff.cpp. Tệp globals.cpp khởi tạo một số biến ngoại lệ được sử dụng trong stuff.cpp. Vấn đề tôi gặp phải là mã trong stuff.cpp đang chạy trước khi mã trong globals.cpp đã có cơ hội gán giá trị cho các biến bên ngoài. Ví dụ: tôi thấy một loạt các giá trị 0 đang được sử dụng. Vấn đề này phụ thuộc vào nền tảng tôi biên dịch/chạy mã trên - một số công việc và một số thì không.Tại sao biến ngoài của tôi chưa được khởi tạo?

Làm cách nào để giải quyết vấn đề này? Tôi có thể buộc globals.cpp đến chạy trước tiên không?

+3

Bạn đang gặp [fiasco thứ tự khởi tạo tĩnh] [1]. [1]: http://stackoverflow.com/questions/3035422/static-initialization-order-fiasco – kfmfe04

+0

Xin cảm ơn, ít nhất hãy giải quyết vấn đề. – sholsapp

Trả lời

6

Bạn không thể (theo cách nhất quán)

Nhưng bạn có thể làm việc xung quanh nó.

global.cpp

// If you have a global variable that has to be initial by a constructor 
MyObj globalX; 

// Instead do this 

MyObj& globalX() { static MyObj x; return x;} 

Bạn vẫn có một biến toàn cầu. Nhưng bằng cách đặt nó vào một hàm chúng ta biết khi nào nó đang được sử dụng. Bằng cách sử dụng một thành viên tĩnh của hàm, nó được khởi tạo lần đầu khi hàm được gọi nhưng không phải sau đó. Vì vậy, bạn biết rằng nó sẽ được xây dựng chính xác trước khi sử dụng lần đầu tiên.

+0

Điều này giải quyết được vấn đề. – sholsapp

2
+0

Như thường lệ, Câu hỏi thường gặp đưa ra lời khuyên không tốt. Sử dụng con trỏ có nghĩa là các đối tượng không bị phá hủy liên tục và điểm tiếp theo về các vấn đề với thứ tự hủy diệt chỉ đơn giản là sai: http: // stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems # 335746 –

+0

@LokiAstari: Thú vị. Nó hoàn toàn sai? Câu hỏi thường gặp đề cập đến "Nếu các nhà thầu của a, b và c sử dụng ans, bạn nên bình thường vì hệ thống thời gian chạy sẽ, trong quá trình khởi tạo tĩnh, hủy ans sau khi ba đối tượng cuối cùng bị hủy.", Mặc dù tôi đồng ý không nên bỏ qua nó. – jamesdlin

+0

Ông loại bỏ rò rỉ không phải là một vấn đề bởi vì bộ nhớ được làm sạch bởi hệ điều hành. Đây chỉ là ** cẩu thả và BAD **. Bất cứ điều gì với một constructor/destructor thì nó không thực sự là bộ nhớ; về các nguồn tài nguyên mà các đối tượng này giữ và làm sạch chúng. Có thể có bất kỳ thứ gì trong các đối tượng này và khi bạn sửa đổi một đối tượng, bạn kiểm tra tất cả các địa điểm bạn cố ý rò rỉ để đảm bảo sự rò rỉ không ảnh hưởng đến độ chính xác của mã của bạn (Iam đoán bạn thậm chí không thể tìm thấy những địa điểm này). Vì vậy, thời gian duy nhất bình luận của ông là có liên quan là cho các công cụ không có constructor/destructor. –

0

tôi giả sử bạn đang nhìn thấy behavious này bởi vì bạn đang làm khởi inline của biến toàn cục mà không có một cuộc gọi hàm rõ ràng. ví dụ. globals.cpp:

// top of source file 

#include "myincludes.h" 

CSomeClass someObject(432); 
int global_x = 42; 
int global_y = InitY(); 

Trình xây dựng và thứ tự hủy của các đối tượng toàn cầu và trật tự khởi tạo biến toàn cầu hầu như không xác định. (Tôi sẽ phỏng đoán, không tham khảo các trang tham chiếu chuẩn, các biến trong tệp nguồn được khởi tạo từ khai báo trên xuống dưới, nhưng thứ tự của "tệp nguồn đến trước" không được xác định.)

Giải pháp tốt nhất là để không có bất kỳ đối tượng toàn cầu nào (nơi hàm tạo được chạy trước bất kỳ hàm nào trong thư viện) hoặc có một sự phụ thuộc vào thứ tự khởi tạo biến toàn cầu.

Tốt hơn để có chức năng khởi tạo thư viện của bạn một cách rõ ràng. Có lẽ bạn yêu cầu ứng dụng gọi hàm này khi khởi động hoặc các chức năng đã xuất của thư viện của bạn gọi nó sau khi phát hiện khởi tạo đã không xảy ra. Khởi tạo các hình cầu của bạn sau đó.

Trên nhóm của tôi, mã chạy trước "chính" (hoặc "DllMain") hoàn toàn không được phép. Nói cách khác, không có đối tượng toàn cầu. Không có chức năng để init globals.

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