2009-10-08 13 views
5

Tôi đã đọc Qt ước mã hóa tài liệu và đến khi đoạn như sau:C++ tĩnh toàn cầu phi POD: lý thuyết và thực hành

Bất cứ điều gì mà có một nhà xây dựng hoặc cần phải chạy mã được khởi tạo có thể không được sử dụng như là đối tượng toàn cầu trong mã thư viện, vì nó không được định nghĩa khi hàm khởi tạo/mã đó sẽ được chạy (lần đầu tiên sử dụng, trên tải thư viện, trước chính() hoặc không phải ở tất cả). Ngay cả khi thời gian thực hiện của bộ khởi tạo được xác định cho thư viện được chia sẻ, bạn sẽ gặp rắc rối khi di chuyển mã đó trong plugin hoặc nếu thư viện được biên dịch tĩnh.

Tôi biết những gì theory nói, nhưng tôi không hiểu phần "không hề". Đôi khi tôi sử dụng không phải POD const toàn cầu statics (ví dụ: QString) và nó không bao giờ xảy ra với tôi rằng họ có thể không được khởi tạo ... Điều này cụ thể cho các đối tượng chia sẻ/DLLs? Điều này có xảy ra với các trình biên dịch bị hỏng không?

Bạn nghĩ gì về quy tắc này?

+0

QString của bạn có thể không được khởi tạo nếu bạn không sử dụng chúng. Nhưng nếu bạn sử dụng chúng, chúng sẽ được khởi tạo. Ngay cả khi điều này chỉ là trước khi sử dụng (tức là ngay trước khi một mthod được gọi trên đối tượng). –

Trả lời

8

Phần "không hề" chỉ đơn giản nói rằng tiêu chuẩn C++ là im lặng về vấn đề này. Nó không biết về các thư viện chia sẻ và do đó không nói bất cứ điều gì về sự tương tác của một số tính năng C++ với những điều này. Trong thực tế, tôi đã nhìn thấy toàn cầu không POD chung được sử dụng trên Windows, OSX, và nhiều phiên bản của Linux và các Unices khác, cả trong GUI và các chương trình dòng lệnh, như bổ trợ và các ứng dụng độc lập. Ít nhất một dự án (sử dụng các hình cầu tĩnh không POD) có các phiên bản cho tập hợp đầy đủ tất cả các kết hợp này. Vấn đề duy nhất mà tôi từng thấy là một số phiên bản GCC đã được tạo cũ, được gọi là các dtors của các đối tượng như vậy trong các thư viện động khi thực thi dừng lại, không phải khi thư viện được dỡ bỏ. Tất nhiên, điều đó đã gây tử vong (mã thư viện được gọi khi thư viện đã biến mất), nhưng điều đó đã gần một thập kỷ trước.

Nhưng tất nhiên, điều này vẫn không đảm bảo bất cứ điều gì.

2

Tôi không nghĩ rằng các nhà thầu đối tượng tĩnh có thể được elided. Có thể là một sự nhầm lẫn với thực tế là một thư viện tĩnh thường chỉ là một bó của các đối tượng được mã thông báo trong thực thi nếu chúng được tham chiếu. Một số đối tượng tĩnh được thiết kế để chúng không được tham chiếu bên ngoài đối tượng chứa của chúng, và vì vậy tệp đối tượng được đặt trong tệp thực thi chỉ khi có một sự phụ thuộc khác vào chúng. Đây không phải là trường hợp trong một số mẫu (sử dụng một đối tượng tĩnh tự đăng ký ví dụ).

+0

Tôi nghĩ bạn đang bối rối "đối tượng tĩnh" với "thư viện tĩnh". – sbi

+1

Bởi "đối tượng tĩnh" tôi có nghĩa là "đối tượng có thời gian lưu trữ tĩnh". BTW, tôi đã tìm thấy các tài liệu tham khảo nói rằng họ không thể được gỡ bỏ nếu khởi tạo hoặc destructor của họ có tác dụng phụ: 3.7.1/2. – AProgrammer

+0

Tôi có nghĩa là các thư viện tĩnh rất có thể không phải là vấn đề ở đây. Đó là thư viện động, đó là vấn đề. – sbi

2

Nếu đối tượng tĩnh được xác định trong đối tượng không được tham chiếu, trình liên kết có thể cắt hoàn toàn đối tượng, bao gồm mã khởi tạo tĩnh. Nó sẽ làm như vậy thường xuyên cho libs (đó là cách libc không được liên kết hoàn toàn khi sử dụng các phần của nó dưới gnu, ví dụ).

Thật thú vị, tôi không nghĩ điều này là cụ thể đối với thư viện. Nó có thể có thể xảy ra cho các đối tượng ngay cả trong xây dựng chính.

2

Tôi thấy không có vấn đề gì với việc có các đối tượng chung với các nhà xây dựng.

Chúng chỉ nên không có bất kỳ sự phụ thuộc nào vào các đối tượng toàn cục khác trong hàm tạo (hoặc hàm hủy).

Nhưng nếu chúng có phụ thuộc thì đối tượng phụ thuộc phải trong cùng một đơn vị biên dịch hoặc được đánh giá lazily để bạn có thể buộc nó được đánh giá trước khi bạn sử dụng nó.

Mã trong hàm khởi tạo cũng không phụ thuộc vào thời điểm (điều này liên quan đến phụ thuộc nhưng không hoàn toàn giống nhau) được thực thi, nhưng bạn an toàn cho rằng nó sẽ được xây dựng ít nhất (trước đây một phương thức được gọi) và C++ đảm bảo trật tự hủy diệt là ngược lại của sự khởi tạo.

Không quá khó để tuân thủ các quy tắc này.

2

C++ không xác định thứ tự mà bộ khởi tạo tĩnh thực hiện cho các đối tượng trong các đơn vị biên dịch khác nhau (thứ tự được xác định rõ trong một đơn vị biên dịch).

Hãy xem xét trường hợp bạn có 2 đối tượng tĩnh A và B được xác định trong các đơn vị biên dịch khác nhau. Giả sử đối tượng B thực sự sử dụng đối tượng A trong khởi tạo của nó.

Trong trường hợp này, có thể B sẽ được khởi tạo trước và thực hiện cuộc gọi đối với đối tượng A chưa được khởi tạo. Đây có thể là một điều có nghĩa là "không hề" - một đối tượng đang được sử dụng khi nó không có cơ hội để khởi tạo nó trước tiên (ngay cả khi nó có thể được khởi tạo sau này).

Tôi cho rằng liên kết động có thể làm tăng thêm sự phức tạp mà tôi chưa từng nghĩ rằng một đối tượng không bao giờ được khởi tạo. Dù bằng cách nào, dòng dưới cùng là tĩnh initializatino giới thiệu đủ các vấn đề tiềm năng mà nó nên tránh khi có thể và rất cẩn thận xử lý, nơi bạn phải sử dụng nó.

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