2012-02-10 26 views
9

Tôi đã thường quen với việc thực hiện một mô hình singleton theo cách này vì nó rất dễ dàng:Có vấn đề với việc triển khai singleton này không?

class MyClass 
{ 
    public: 
     MyClass* GetInstance() 
     { 
      static MyClass instance; 
      return &instance; 
     } 

    private: 
     //Disallow copy construction, copy assignment, and external 
     //default construction. 
}; 

Điều này có vẻ dễ dàng hơn so với việc tạo ra một con trỏ dụ tĩnh, khởi tạo nó trong tập tin nguồn, và sử dụng bộ nhớ động đáng kể phân bổ trong các chức năng dụ với bảo vệ.

Có một nhược điểm mà tôi không thấy không? Có vẻ như thread-an toàn với tôi bởi vì tôi sẽ nghĩ rằng thread đầu tiên để có được đến dòng đầu tiên sẽ gây ra instantiation - và nó có vẻ tốt đẹp và súc tích. Tôi thấy có phải là một vấn đề tôi không thấy vì điều này không phổ biến mặc dù tôi muốn nhận được một số phản hồi trước khi tôi tiếp tục sử dụng nó

+2

Bạn có thể trả lại MyClass & thay vì MyClass * –

+10

Ý của bạn, ngoài thực tế là đó là một singleton? http: // stackoverflow.com/q/137975/10077 –

+0

Yeah, yeah Tôi biết họ là một anti-pattern và nên tránh :) Tôi vẫn quan tâm đến lý do tại sao điều này có thể không được thread-an toàn mặc dù. Tôi biết việc sửa đổi các thành viên dữ liệu của singleton nên được bảo vệ bằng mutex, nhưng tôi nghĩ rằng việc tạo ra thông qua chức năng này sẽ an toàn. –

Trả lời

3

Đây không phải là giải pháp luồng an toàn vốn có: trong khi xây dựng cá thể, một chuỗi khác có thể được ưu tiên và cố gắng lấy cá thể, dẫn đến một cá thể kép hoặc sử dụng một cá thể không được cấu trúc.

Điều này được xử lý bởi một số trình biên dịch bằng cách thêm một bảo vệ (trong gcc, tôi nghĩ rằng có một lá cờ để vô hiệu hóa điều này) vì không có cách nào để bảo vệ điều này với một mutex userdefined.

+0

Vì vậy, bạn đang nói rằng thậm chí biết có một biến tĩnh ở đây, nhiều hơn một trong số đó có thể được tạo ra bằng cách nào đó? –

+0

Ví dụ được khởi tạo khi sử dụng lần đầu tiên của hàm. Tôi đoán nó được khởi tạo gấp đôi so với ví dụ kép. – stefaanv

+0

Tôi đã nghĩ rằng thread đầu tiên để đạt được dòng với static sẽ kích hoạt nó tạo/khởi tạo và thread thứ hai nhấn dòng đó sẽ nhận thức đầy đủ về việc tạo và khởi tạo vì cách thức làm việc của statics. Tại sao điều đó không đúng? –

0

Bên cạnh trong một tình huống đa luồng - không. Vâng - hãy để tôi đủ điều kiện này, xây dựng là lười biếng (vì vậy cuộc gọi đầu tiên có thể có một hit) và hủy diệt - tốt, không có bảo lãnh (ngoài nó sẽ được - tại một số điểm)

3

Nhược điểm là bạn có không kiểm soát chính xác khi đối tượng bị phá hủy. Điều này sẽ là một vấn đề nếu các đối tượng tĩnh khác cố gắng truy cập nó từ các destructors của chúng.

Trình biên dịch tuân thủ C++ 11 phải thực hiện điều này theo cách an toàn; tuy nhiên, các trình biên dịch cũ hơn có thể không. Nếu bạn đang nghi ngờ, và bạn không đặc biệt muốn khởi tạo lười biếng, bạn có thể buộc đối tượng được tạo ra bằng cách gọi trình truy cập trước khi bắt đầu bất kỳ chủ đề nào.

+0

Vì vậy, bạn đang nói rằng mặc dù có một tĩnh trong hàm đó, trong các trình biên dịch không phải C++ 11 nó có thể được tạo ra gấp đôi? nhưng miễn là tôi gọi hàm thể hiện trước khi vào giai đoạn đa luồng của mã, đó là tạo luồng an toàn? chỉ làm rõ :) Cảm ơn câu trả lời cho đến nay! –

+0

@ w00te: Vâng, đúng vậy. Trước C++ 11, tiêu chuẩn không có gì để nói về an toàn luồng, do đó, nó hoàn toàn phụ thuộc vào việc thực hiện trình biên dịch có bảo vệ chống lại việc tạo đôi hay không. Nó nên được thread an toàn với hầu hết các trình biên dịch hợp lý gần đây. –

+0

+1 Cảm ơn sự giúp đỡ của bạn, thật tuyệt khi biết nó là phiên bản tiêu chuẩn cụ thể. –

2

Có hai vấn đề trong giao diện:

  • Bạn nên trả lại một tham chiếu
  • Bạn nên thực hiện một trong hai destructor hoặc delete hành private

Ngoài ra, có một nguy cơ nhẹ cố gắng sử dụng lớp này sau khi nó bị hủy.

Về mối quan tâm đa luồng của bạn (và khởi tạo tôi đoán): nó tốt trong C++ 11 và đã tốt trong một thời gian dài trên trình biên dịch C++ tốt anyway.

+0

+1 cảm ơn bạn đã giúp đỡ :) –

0

Nói chung, trình độ chuyên môn static cho biến cục bộ trong một phương thức không đảm bảo rằng biến được tạo chỉ một lần. Nếu phương thức này được gọi bởi các luồng khác nhau, nó có thể được tạo một lần cho mỗi luồng quá nhiều lần, như nhiều luồng được gọi nó. Nó không nên nhầm lẫn với thành viên tĩnh của lớp, được tạo ra một lần trước khi chương trình được bắt đầu. Độ an toàn của các biến tĩnh cục bộ phụ thuộc vào việc thực hiện cụ thể của C++. Liên kết hữu ích: Are function static variables thread-safe in GCC?

Hy vọng điều đó sẽ hữu ích.

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