2012-01-09 9 views
33

Những gì tôi biết về C++ là thứ tự của các công trình (và hủy) của các cá thể toàn cầu không nên được giả định.Là std :: cout đảm bảo được khởi tạo?

Trong khi tôi đang viết mã với một cá thể chung sử dụng std::cout trong hàm tạo & destructor, tôi có một câu hỏi.

std::cout cũng là phiên bản toàn cục của iostream. Có phải std::cout được đảm bảo được khởi chạy trước bất kỳ phiên bản toàn cầu nào khác không?

Tôi đã viết một mã kiểm tra đơn giản và nó hoạt động hoàn hảo, nhưng tôi vẫn không biết tại sao.

#include <iostream> 

struct test 
{ 
    test() { std::cout << "test::ctor" << std::endl; } 
    ~test() { std::cout << "test::dtor" << std::endl; } 
}; 

test t; 

int main() 
{ 
    std::cout << "Hello world" << std::endl; 
    return 0; 
} 

It in

test::ctor 
Hello world 
test::dtor 

Có bất kỳ khả năng rằng mã không chạy như mong đợi?

+1

Liên quan đến http://stackoverflow.com/questions/6919593/is-cout-guaranteed-available-during-static-deinitialization cũng bao gồm việc xây dựng trong câu trả lời. – adl

+0

Thứ tự khởi tạo của các đối tượng thời gian lưu trữ tĩnh ở phạm vi toàn cục không thể giả định được nhưng có các thủ thuật để buộc thứ tự khởi tạo. –

+0

PS.Cũng lưu ý thứ tự hủy diệt được đảm bảo (nghịch đảo của việc xây dựng). –

Trả lời

36

Câu trả lời khác nhau tùy thuộc vào việc bạn đang sử dụng C++ 03 hoặc C++ 11.

Trong C++ 11, mã của bạn được đảm bảo hoạt động, nhưng trong C++ 03 nó không được chỉ định; đảm bảo duy nhất của bạn là vào thời điểm main() được nhập, luồng tiêu chuẩn đã được khởi tạo. (Điều đó nói rằng, tất cả hiện thực chủ đạo khởi tạo chúng trước khi chạy bất kỳ khởi động, làm cho chúng tốt để sử dụng.)

Bạn có thể buộc khởi bằng cách xây dựng một đối tượng std::ios_base::Init, như vậy:

#include <iostream> 

struct test 
{ 
    test() { std::cout << "test::ctor" << std::endl; } 
    ~test() { std::cout << "test::dtor" << std::endl; } 

private: 
    std::ios_base::Init mInitializer; 
}; 

test t; 

int main() 
{ 
    std::cout << "Hello world" << std::endl; 
    return 0; 
} 

Bây giờ khi test các cấu trúc, nó khởi tạo mInitializer và đảm bảo các luồng đã sẵn sàng để sử dụng.

C++ 11 cố định hành vi hơi khó chịu này bằng cách hành động như thể mọi trường hợp của #include <iostream> được theo sau bởi static std::ios_base::Init __unspecified_name__;. Điều này tự động đảm bảo các luồng đã sẵn sàng để sử dụng.

+2

Trong C++ 03 ý định rõ ràng (như được chỉ ra bởi nốt chân) là đảm bảo rằng các đối tượng std :: cin/std :: cout được xây dựng hoàn chỉnh trước các đối tượng khác. –

10

Theo §27.3/2:

Đối tượng [std :: cin, std :: cout, vv] được xây dựng, và các hiệp hội được thành lập tại một số thời gian trước hoặc trong thời gian đầu tiên thời gian một đối tượng của lớp ios_base :: Init được xây dựng, và trong mọi trường hợp trước khi cơ quan bắt đầu thực hiện chính.

+1

Không nói gì về thứ tự xây dựng 'std :: cout' liên quan đến các đối tượng tĩnh khác. –

+10

@BasileStarynkevitch: Phân loại đúng, nhưng chú thích 265 (tham chiếu từ §27.3/2) cho biết nó sẽ hoạt động: "Constructors và destructors cho các đối tượng tĩnh có thể truy cập các đối tượng này để đọc đầu vào từ stdin hoặc ghi đầu ra để stdout hoặc stderr." Điều đó có thể không mang tính quy phạm, nhưng nêu rõ ít nhất là * ý định * rằng mã của anh ta nên hoạt động. –

+3

@BasileStarynkevitch: Nó thực sự có. Đoạn văn tiếp tục: "Kết quả bao gồm trong đơn vị dịch sẽ như thể đã xác định một phiên bản của ios_base :: Init với thời gian lưu trữ tĩnh". Và vì các biến tĩnh không phải cục bộ trong cùng một đơn vị dịch được khởi tạo theo thứ tự khai báo, 'cout' được đảm bảo đã được khởi tạo trước các số liệu thống kê không phải cục bộ khác của bạn. (Giả sử bạn '#include ' trước khi bạn khai báo các biến của mình, mà tôi chân thành hy vọng) – knatten

2

Câu hỏi của bạn là về thứ tự xây dựng các đối tượng tĩnh. Tôi tin rằng các đặc điểm kỹ thuật ngôn ngữ lá nó không xác định.

GCC có thuộc tính init_priority để phát theo thứ tự.

Và tôi tin rằng bạn không nên lo lắng nhiều trong thực tế.