2009-03-11 24 views
5

Trong C++, giả sử bạn muốn khai báo một biến toàn cầu được nhiều người sử dụng. Bạn làm nó như thế nào?Cách tốt nhất để khai báo biến toàn cầu là gì?

Tôi thường sử dụng khai báo và xác định trong tệp cpp, sau đó sử dụng extern trong tệp cpp khác (và không phải tiêu đề).

tôi không thích cách tiếp cận này, và tôi đang xem xét một cái gì đó dọc theo những dòng:

Trong một tập tin tiêu đề:

some_file.h

Class MYGlobalClass 
{ 

}; 


MyGlobalClass& MyGlobalClassInstance() 
{ 
    static MYGlobalClass instance; 
    return instance; 

} 

Sửa

Hãy xem xét trong các ngữ cảnh sau:

  • thể được sử dụng trong các ứng dụng đa luồng
  • ô nhiễm không gian tên
  • có thể KHÔNG necessery là một singleton, như nhiều trường hợp điều này có thể được tạo ra

suy nghĩ của bạn là gì, đề xuất, ý tưởng mới?

+0

Mẫu thiết kế Singleton –

+0

Không phải là một ý kiến ​​hay, hãy xem các nhận xét bên dưới –

+0

Biến toàn cục, trong đó bạn muốn tạo một vài phiên bản? Có vẻ như bạn vẫn cần phải xây dựng một chút ... – Reunanen

Trả lời

2

Khai báo nó trong một tệp tiêu đề (sử dụng extern) và xác định nó trong một.cpp (hoặc bất kỳ tiện ích mở rộng nào khác). Bạn có thể sử dụng hàm và trả về tham chiếu đến biến tĩnh như bạn đã trình bày để giải quyết các vấn đề với thứ tự xây dựng liên quan đến các biến phạm vi không gian tên khác trong các tệp .cpp khác. Nhưng hãy nhớ rằng sẽ không bảo vệ bạn khỏi các vấn đề trật tự hủy diệt - đó là thứ tự ngược lại chính xác từ việc xây dựng (những thứ này được gọi là "fiasco trật tự khởi tạo tĩnh" .Nếu bạn sử dụng một hàm giống như của bạn và đặt nó vào tiêu đề, hãy làm cho nó trở thành nội tuyến để xác định lại chức năng hợp lệ khi nó được đưa vào nhiều tập tin .cpp (một cách hợp lý, chức năng này vẫn chỉ rõ ràng một lần, vì tĩnh trong nó sẽ chỉ tồn tại một lần, chứ không phải riêng cho mỗi tập tin được đưa vào). khai báo nó trong một tiêu đề nhưng xác định nó trong một.cpp tệp (nhưng sau đó, loại bỏ nội tuyến khỏi nó!).

inline A& getA() { static A a; return a; } 

Những vấn đề tiềm năng với trật tự phá hủy có thể được phá vỡ bằng cách sử dụng new:

inline A& getA() { static A *a = new A; return *a; } 

Destructor của nó, tuy nhiên, sẽ không bao giờ được gọi sau đó. Nếu bạn cần an toàn luồng, bạn nên thêm một mutex bảo vệ chống lại nhiều lần truy cập. boost.thread có thể có một cái gì đó cho điều đó.

+0

các vấn đề với trật tự hủy diệt là gì? – yesraaj

+0

đó là thứ tự ngược lại chính xác của xây dựng. tức là nếu một đối tượng được tạo ra trước khi bạn gọi hàm getA() lần đầu tiên, thì nó sẽ bị hủy sau đối tượng trong hàm getA(). I.e có một thứ tự cụ thể. Ví dụ, nếu bạn truy cập getA() trong đối tượng destructor, bạn sẽ truy cập một tham chiếu lơ lửng. –

+0

tìm kiếm "fiasco trật tự khởi tạo tĩnh" và tôi nghĩ bạn sẽ tìm thấy một vài lời giải thích (dài hơn tổng quan ngắn của tôi ở đây, tất nhiên) về sự kỳ quặc đó. –

0

extern MyGlobalClass MyGlobalClassInstance;

Chỉnh sửa: Không tĩnh>. <

+0

tĩnh sẽ không hoạt động, tôi cần chia sẻ nó qua các tệp, mô-đun hoặc thậm chí là thư viện. cảm ơn thời gian của bạn mặc dù –

4

Declare như extern trong một tập tin tiêu đề bao gồm bởi "nhiều" và định nghĩa nó trong một tập tin * .cpp

+0

Ý tưởng hay! có lẽ xác định một hàm nội tuyến trong tệp tiêu đề? và bao gồm tiêu đề của nhiều người? –

+0

Không có trường học như trường học cũ. – chaos

1

khai báo và xác định trong tập tin cpp

Giữ khai -ed extern trong tiêu đề. Xác định nó chỉ một lần trong tệp triển khai.

Bạn đang đóng cửa. Sử dụng một không gian tên thay thế cho các biến toàn cục.

namespace myns { 
    int foo = 0; 
} 

Bây giờ, nếu là đối tượng lớp, bạn đang xem mẫu Singletion. Trong thực tế, mã mẫu của bạn phản ánh một thiết kế Singleton. Tuy nhiên, nếu bạn định xác định hàm trong tiêu đề, hãy làm cho nó nội tuyến - vi phạm ODR nếu không.

+0

Tôi đã xem xét không gian tên .... –

+0

Bạn đang nghĩ về một đối tượng Singleton. Trong trường hợp đó có một accessor và sử dụng nó. Tất nhiên, bạn vẫn cần bao gồm tiêu đề. Hãy xem.http: //en.wikipedia.org/wiki/Singleton_pattern – dirkgently

+0

Cảm ơn bạn, tôi đã quen thuộc với Singleton. Tuy nhiên, đó không phải là giải pháp mà tôi đang tìm kiếm. –

-1

Tại sao không sử dụng mẫu Singleton cũ tốt?

+0

Vì nó chỉ thêm các vấn đề mới, và không giải quyết vấn đề anh ta cần giải quyết – jalf

+0

Tôi không muốn chỉ một ví dụ của lớp đó! cộng với một chi phí không cần thiết –

+0

Nhưng mã bạn đã viết là một singleton với chính xác một ví dụ tĩnh !! –

2

Ý tưởng của bạn về một hàm tĩnh bên trong hàm truy nhập khác biệt đáng kể so với biến toàn cầu. Sự khác biệt là khi nó được xây dựng, và rất có thể là một vấn đề lớn với nhiều luồng. Nếu hai chủ đề gọi MyGlobalClassInstance cùng một lúc thì sao? Tùy thuộc vào môi trường, nhưng tôi nghi ngờ đây là điển hình của hầu hết các trình biên dịch C++, bạn sẽ có khả năng nhận được hai cuộc gọi đến hàm tạo của MyGlobalClass chạy cùng một lúc, giải quyết cùng một vùng bộ nhớ.

Nếu bạn là đơn luồng, ít có khả năng là sự cố.

Nếu bạn khai báo cá thể dưới dạng thành viên tĩnh bình thường hoặc biến toàn cầu bình thường trong tệp nguồn, có thể bạn sẽ có thời gian dễ dàng hơn, bởi vì hàm tạo sẽ được gọi trước khi thực hiện trước khi bạn thực hiện trước khi bạn có cơ hội bắt đầu các chủ đề khác.

+0

Mặt khác, nếu bạn khai báo một biến toàn cầu đơn giản, bạn sẽ gặp phải tất cả các vấn đề với thứ tự khởi tạo không thể đoán trước. – jalf

+0

Đúng. Không phải là C++? :) –

+0

yep :) (10 chars đệm) – jalf

1

Nó nó thực sự là một biến toàn cầu mà về mặt lý thuyết có thể được truy cập từ bên ngoài bởi bất kỳ mô-đun, bạn nên đặt việc khai báo extern trong file header:

// MyClass.h 
class MyClass { ... }; 
extern MyClass myGlobalInstance; 

// MyClass.cpp 
MyClass myGlobalInstance; 

Nếu nó chỉ là một đối tượng toàn cầu mà nên thực sự chỉ được truy cập bởi một mô-đun đơn, giới hạn phạm vi của nó bằng cách biến nó thành biến lớp tĩnh riêng (hoặc được bảo vệ), một biến chức năng tĩnh (nếu nó chỉ cần một hàm), hoặc trong một không gian tên ẩn danh:

Tùy chọn 1:

// MyClass.h 
class MyClass 
{ 
private: // or protected, if you want it accessible by subclasses 
    static MyClass myGlobalInstance; 
}; 

Phương án 2:

// MyClass.cpp 
void someFunction() 
{ 
    // it's global, but only accessible inside this function 
    static MyClass myGlobalInstance; 
    ... 
} 

Lựa chọn 3:

// MyClass.cpp 
namespace 
{ 
    MyClass myGlobalInstance; 
} 

// it's now only accessible in this file 
10

Lời khuyên tốt nhất có lẽ là "cố gắng tránh globals". Mọi người không cần biến toàn cầu thường xuyên như họ nghĩ. Thông thường nó chỉ ra rằng "vượt qua tất cả mọi thứ như là đối số để xây dựng" không phải là khá nhiều công việc như mọi người nghĩ rằng khi họ nghe đề nghị. Nó cũng có xu hướng dẫn đến mã sạch hơn với ít hơn, và rõ ràng hơn, phụ thuộc.

Tôi không biết bất kỳ cách "chính xác" nào để khai báo các hình cầu trong C++. Cách bạn làm điều đó bây giờ hoạt động tốt, nhưng thứ tự khởi tạo không được chỉ định, vì vậy nếu có bất kỳ sự phụ thuộc nào giữa các hình cầu của bạn, bạn đang gặp rắc rối.

Một hàm trả về một cá thể tĩnh ít nhiều giải quyết được vấn đề đó, nhưng không phải là luồng an toàn.

Và một singleton chỉ là một ý tưởng tồi tệ. Nó không giải quyết vấn đề của bạn, nhưng thêm các ràng buộc bổ sung vào mã của bạn, điều này không thực sự cần thiết, và rất có thể sẽ trở lại và cắn bạn sau này.

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