সি ++ সিঙ্গলটন ডিজাইনের প্যাটার্ন


734

সম্প্রতি আমি সি ++ এর জন্য সিঙ্গেলটন ডিজাইনের ধরণটির উপলব্ধি / বাস্তবায়নে ঝাঁপিয়ে পড়েছি। এটি দেখতে এরকম দেখাচ্ছে (আমি এটি বাস্তব জীবনের উদাহরণ থেকে গ্রহণ করেছি):

// a lot of methods are omitted here
class Singleton
{
   public:
       static Singleton* getInstance( );
       ~Singleton( );
   private:
       Singleton( );
       static Singleton* instance;
};

এই ঘোষণা থেকে আমি অনুমান করতে পারি যে দৃষ্টান্ত ক্ষেত্রটি গাদা দিয়ে শুরু হয়েছিল। তার মানে একটি স্মৃতি বরাদ্দ আছে। আমার জন্য সম্পূর্ণ অস্পষ্ট যখন হুবহু স্মৃতি হ্রাস করতে চলেছে? বা বাগ এবং মেমরি ফুটো আছে? দেখে মনে হচ্ছে বাস্তবায়নে কোনও সমস্যা আছে।

আমার মূল প্রশ্নটি হল, আমি কীভাবে এটি সঠিক উপায়ে প্রয়োগ করব?



10
আপনি এই কাগজটিতে সি ++ তে থ্রেড-সুরক্ষা সহ একক সিঙ্গলটন কীভাবে প্রয়োগ করতে হবে তার একটি দুর্দান্ত আলোচনা পাবেন। aristeia.com

106
@ এসবিআই - কেবলমাত্র একটি সিথ রহস্যজনক বিষয় নিয়ে কাজ করে। সিঙ্গলেটস ছাড়াই কি বেশিরভাগ সমস্যার সমাধান করা যায়? একেবারে। সিঙ্গলেটগুলি কি তাদের নিজস্ব সমস্যা সৃষ্টি করে? হ্যাঁ. তবে, আমি সত্যই বলতে পারি না যে সেগুলি খারাপ , কারণ নকশা হ'ল ট্রেড অফগুলি বিবেচনা করা এবং আপনার পদ্ধতির সংক্ষিপ্তসারগুলি বোঝার about
derekerdmann

11
@ ডেরেকারডম্যান: আমি বলিনি যে আপনার কখনই বৈশ্বিক পরিবর্তনশীল প্রয়োজন হয় না (এবং যখন আপনার প্রয়োজন হয় তখন সিঙ্গলটন কখনও কখনও ভাল হয়)। আমি যা বলেছিলাম তা হ'ল এগুলি যতটা সম্ভব কম ব্যবহার করা উচিত। সিঙ্গেলটনকে মূল্যবান ডিজাইনের প্যাটার্ন হিসাবে গ্লোরিফাইং করা ছাপ দেয় যে এটি হ্যাক , এর চেয়ে কোডটি বোঝা শক্ত, বজায় রাখা শক্ত এবং পরীক্ষা করা শক্ত। এই কারণেই আমি আমার মন্তব্য পোস্ট করেছি। আপনি এখন পর্যন্ত যা বলেছিলেন তার কোনওটিই এর বিরোধিতা করছে না।
sbi

13
@ এসবিআই: আপনি যা বলেছিলেন তা "সেগুলি ব্যবহার করবেন না"। আপনি যেহেতু পরিবর্তিত হয়েছিলেন তার চেয়ে বেশি যুক্তিসঙ্গত "এগুলি যতটা সম্ভব কম ব্যবহার করা উচিত" নয় - অবশ্যই আপনি পার্থক্যটি দেখেন।
jwd

উত্তর:


1105

২০০৮ সালে আমি সিঙ্গেলটন ডিজাইন প্যাটার্নের একটি সি ++ 98 বাস্তবায়ন প্রদান করেছি যা অলস-মূল্যায়ন, গ্যারান্টেড-ধ্বংস, প্রযুক্তিগতভাবে থ্রেড-নিরাপদ নয়:
কেউ আমাকে সি ++ এ সিঙ্গেলনের নমুনা সরবরাহ করতে পারেন?

অলস-মূল্যায়ন, সঠিকভাবে ধ্বংস, এবং থ্রেড-নিরাপদ সিঙ্গলটন ডিজাইন প্যাটার্নটির এখানে একটি আপডেট করা সি ++ 11 বাস্তবায়ন রয়েছে ।

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {}                    // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Don't forget to declare these two. You want to make sure they
        // are unacceptable otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
    public:
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

        // Note: Scott Meyers mentions in his Effective Modern
        //       C++ book, that deleted functions should generally
        //       be public as it results in better error messages
        //       due to the compilers behavior to check accessibility
        //       before deleted status
};

সিঙ্গলটন কখন ব্যবহার করবেন সে সম্পর্কে এই নিবন্ধটি দেখুন: (প্রায়শই নয়)
সিঙ্গলটন: এটি কীভাবে ব্যবহার করা উচিত

ইনিশিয়ালাইজেশন অর্ডার এবং কীভাবে মোকাবেলা করতে হবে সে সম্পর্কে এই দুটি নিবন্ধ দেখুন:
স্ট্যাটিক ভেরিয়েবল ইনিশিয়ালাইজেশন অর্ডার
সি ++ স্ট্যাটিক ইনিশিয়ালাইজেশন অর্ডার সমস্যাগুলি সন্ধান করুন

লাইফটাইম বর্ণনা করে এই নিবন্ধটি দেখুন:
একটি সি ++ ফাংশনে স্থির পরিবর্তনশীলটির জীবনকাল কত?

এই নিবন্ধটি দেখুন যা সিঙ্গলটনে কিছু থ্রেডিং এর প্রভাবগুলি নিয়ে আলোচনা করেছে:
সিঙ্গলটন উদাহরণটি getInstance পদ্ধতির স্ট্যাটিক ভেরিয়েবল হিসাবে ঘোষিত হয়েছে, এটি থ্রেড-নিরাপদ?

এই নিবন্ধটি দেখুন যা ডাবল চেকড লকিং কেন সি ++ এ কাজ করবে না তা দেখুন:
একটি সাধারণ C ++ প্রোগ্রামার সম্পর্কে জানা থাকা সমস্ত সাধারণ অপরিজ্ঞাত আচরণগুলি কী কী?
ডাঃ ডাবস: সি ++ এবং ডাবল-চেকড লকিংয়ের বিপদ: প্রথম খণ্ড


22
ভাল উত্তর. তবে লক্ষ্য করা উচিত যে এটি থ্রেড-নিরাপদ স্ট্যাকওভারফ্লো
বরুণা

4
@ জোরটনি: আপনি কী করেছেন তা অনেকেই বুঝতে পারে না :)
জোহান জেরেল

4
@ ম্যাক্সিম ইয়েগরোশকিন: এটি ধ্বংস হয়ে গেলে খুব ভালভাবে সংজ্ঞায়িত করা হয় (কোনও অস্পষ্টতা নেই)। দেখুন: স্ট্যাকওভারফ্লো.com
মার্টিন ইয়র্ক

3
What irks me most though is the run-time check of the hidden boolean in getInstance()এটি বাস্তবায়নের কৌশল সম্পর্কে একটি ধারণা। এটি বেঁচে থাকার বিষয়ে কোনও অনুমানের দরকার নেই। দেখতে stackoverflow.com/a/335746/14065 আপনি যে এটা সবসময় (কম ওভারহেড জীবিত তাই একটি অবস্থা জোর করতে পারেন Schwarz counter)। গ্লোবাল ভেরিয়েবলগুলির আরম্ভকরণ আদেশের সাথে আরও সংখ্যক সমস্যা রয়েছে (সংকলন ইউনিট জুড়ে) আপনি কোনও আদেশ জোর করবেন না বলে। এই মডেলের সুবিধাটি হ'ল) ​​অলস সূচনা। 2) একটি আদেশ কার্যকর করার ক্ষমতা (শোয়ার্জ সাহায্য করে তবে সবচেয়ে খারাপ)। হ্যাঁ get_instance()অনেক কদর্য।
মার্টিন ইয়র্ক

3
@ কল: না। এটি স্বাভাবিক নয়। শুধু কারণ, চিন্তাভাবনা ছাড়াই নতুনদের অনুলিপি এবং পেস্ট কোডটি এটিকে স্বাভাবিক হিসাবে তৈরি করে না। আপনার সর্বদা ব্যবহারের ক্ষেত্রে নজর দেওয়া উচিত এবং নিশ্চিত করা উচিত যে অ্যাসাইনমেন্ট অপারেটর প্রত্যাশিতভাবে কি করে। কপি এবং পেস্টিং কোড আপনাকে ত্রুটিগুলির দিকে নিয়ে যেতে চলেছে।
মার্টিন ইয়র্ক

47

সিঙ্গলটন হওয়ায় আপনি সাধারণত এটি ধ্বংস হতে চান না।

প্রোগ্রামটি শেষ হয়ে গেলে এটি ভেঙে যায় এবং বিচ্ছিন্ন হয়ে যায়, যা কোনও সিঙ্গলটনের জন্য স্বাভাবিক, পছন্দসই আচরণ। আপনি যদি পরিষ্কারভাবে এটি পরিষ্কার করতে সক্ষম হতে চান তবে ক্লাসে স্থিতিশীল পদ্ধতি যুক্ত করা মোটামুটি সহজ যা আপনাকে এটিকে একটি পরিষ্কার অবস্থায় ফিরিয়ে আনতে দেয় এবং পরের বার এটি ব্যবহার করার সময় এটি পুনর্বিবেচনা করতে পারে, তবে এটি কোনও ক্ষেত্রের বাইরে নয় a "ক্লাসিক" একক।


4
যদি মুছুন কখনও স্ট্যাটিক সিঙ্গলটন * উদাহরণস্বরূপ স্পষ্টভাবে বলা হয় না, এটি এখনও প্রযুক্তিগতভাবে মেমরি ফাঁস হিসাবে বিবেচিত হবে না?
অ্যান্ড্রু গ্যারিসন

7
এটি বৈশ্বিক ভেরিয়েবলের সাধারণ ঘোষণার চেয়ে স্মৃতি ফাঁস নয়।
ইলিয়া n।

15
কিছু সোজা সেট করতে ... "মেমরি ফাঁস" উদ্বেগ ভিজ-এ-ভিজ সিঙ্গেলনগুলি সম্পূর্ণ অপ্রাসঙ্গিক। আপনার যদি রাষ্ট্রীয় সংস্থানগুলি থাকে যেখানে ডিকনস্ট্রাকশন অর্ডারটি গুরুত্বপূর্ণ, সিলেটলেট বিপজ্জনক হতে পারে; তবে প্রোগ্রামের সমাপ্তিতে অপারেটিং সিস্টেমের মাধ্যমে সমস্ত স্মৃতি পরিষ্কারভাবে ফিরে পাওয়া যায় ... 99.9% ক্ষেত্রে এটি পুরোপুরি একাডেমিক পয়েন্ট বাতিল করে। যদি আপনি ব্যাকরণটি পিছনে পিছনে কী এবং "মেমরি ফুটো" না থেকে তর্ক করতে চান, তবে এটি ঠিক আছে তবে বুঝতে পারেন যে এটি প্রকৃত নকশার সিদ্ধান্তগুলির থেকে একটি ব্যাঘাত।
জেকেরিয়ান

12
@ জাকারিয়ান: মেমরি ফাঁস এবং সি ++ এর প্রসঙ্গে ধ্বংসটি মেমরি ফাঁস সম্পর্কে আসলেই নয়। সত্যিই এটি সম্পদ নিয়ন্ত্রণ সম্পর্কে। যদি আপনি মেমরি ফাঁস করেন তবে ডিস্ট্রোকটরকে ডাকা হয় না এবং এইভাবে অবজেক্টের সাথে যুক্ত কোনও সংস্থান সঠিকভাবে প্রকাশ হয় না। প্রোগ্রামিং শেখানোর সময় মেমরিটি কেবলমাত্র সহজ উদাহরণ যা আমরা ব্যবহার করি তবে সেখানে আরও অনেক জটিল সংস্থান রয়েছে।
মার্টিন ইয়র্ক

7
@ মার্টিন আমি আপনার সাথে পুরোপুরি একমত এমনকি যদি একমাত্র সংস্থানটি মেমোরি হয় তবে আপনার প্রোগ্রামের সত্যিকারের ফাঁসগুলি অনুসন্ধান করার চেষ্টা করতে আপনি এখনও সমস্যায় পড়বেন যদি আপনাকে কোনও প্রশ্নই আসে না, তবে ফাঁসের একটি তালিকা দিয়ে ঝাঁকুনি দিতে হয়। এই সমস্ত পরিষ্কার করা ভাল তাই যে কোনও সরঞ্জাম যা ফাঁসের রিপোর্ট করে কেবল এমন সমস্যাগুলির কারণ হিসাবে রিপোর্ট করে।
ডলফিন

38

আপনি মেমরি বরাদ্দ এড়াতে পারে। অনেকগুলি রূপ রয়েছে, মাল্টিথ্রেডিং পরিবেশের ক্ষেত্রে সকলেরই সমস্যা।

আমি এই ধরণের বাস্তবায়ন পছন্দ করি (আসলে, আমি পছন্দ করি ঠিক এটি বলা হয় না, কারণ আমি যতটা সম্ভব সিলেটলেট এড়িয়ে চলে):

class Singleton
{
private:
   Singleton();

public:
   static Singleton& instance()
   {
      static Singleton INSTANCE;
      return INSTANCE;
   }
};

এটির কোনও গতিশীল মেমরি বরাদ্দ নেই।


3
কিছু ক্ষেত্রে, এই অলস সূচনাটি অনুসরণ করার আদর্শ প্যাটার্ন নয়। একটি উদাহরণ হ'ল যদি সিঙ্গলটনের নির্মাতা গাদা থেকে মেমরি বরাদ্দ করে এবং আপনি চান যে বরাদ্দ অনুমানযোগ্য হয়, উদাহরণস্বরূপ একটি এম্বেডড সিস্টেম বা অন্য শক্তভাবে নিয়ন্ত্রিত পরিবেশে। আমি পছন্দ করি, যখন ক্লাসের স্থির সদস্য হিসাবে উদাহরণটি তৈরি করতে সিঙ্গলটন প্যাটার্নটি সর্বোত্তম প্যাটার্ন ব্যবহার করা হয়।
dma

3
অনেক বড় প্রোগ্রামের জন্য, বিশেষত ডায়নামিক লাইব্রেরি সহ those যে কোনও বৈশ্বিক বা স্থিতিশীল বস্তু যা আদিম নয় সেগুলি লাইব্রেরিটি লোড হওয়ার পরে ধ্বংস সংক্রান্ত সমস্যার ক্রমের কারণে অনেক প্ল্যাটফর্মে প্রোগ্রাম প্রস্থান করার পরে সেগফাল্টস / ক্র্যাশ হতে পারে। বহু কোডিং কনভেনশন (গুগল সহ) অ-তুচ্ছ স্ট্যাটিক এবং গ্লোবাল অবজেক্টের ব্যবহার নিষিদ্ধ করার একটি কারণ এটি।
ওখেকাল্প

দেখে মনে হচ্ছে যে এ জাতীয় বাস্তবায়নের স্থির উদাহরণটির অভ্যন্তরীণ যোগসূত্র রয়েছে এবং এর বিভিন্ন অনুবাদ ইউনিটে অনন্য এবং স্বতন্ত্র অনুলিপি থাকবে যা বিভ্রান্তিকর এবং ভুল আচরণের কারণ হতে পারে। তবে আমি এরকম অনেক বাস্তবায়ন দেখেছি, আমি কি কিছু মিস করছি?
ফেসব্রো

এমন কি একাধিক অবজেক্টে ব্যবহারকারীকে এটি নির্ধারণ করা থেকে বিরত রাখে যেখানে পর্দার পিছনে সংকলক তার নিজস্ব অনুলিপি নির্মাণকারী ব্যবহার করে?
টনি ট্যানুস

19

@ লোকি আস্তারীর উত্তরটি দুর্দান্ত।

তবে একাধিক স্ট্যাটিক অবজেক্টের সাথে এমন সময় রয়েছে যেখানে আপনার গ্যারান্টি দিতে সক্ষম হওয়া দরকার যে আপনার সমস্ত স্ট্যাটিক অবজেক্টস যারা সিঙ্গলটনের ব্যবহার করে না, ততক্ষণ সিঙ্গলটন ধ্বংস হবে না ।

এই ক্ষেত্রে std::shared_ptrরাখা ব্যবহার করা যেতে পারে Singleton সকল ব্যবহারকারীর এমনকি যখন স্ট্যাটিক destructors প্রোগ্রাম শেষে আহবান করা হয় বেচে:

class Singleton
{
public:
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    static std::shared_ptr<Singleton> instance()
    {
        static std::shared_ptr<Singleton> s{new Singleton};
        return s;
    }

private:
    Singleton() {}
};

9

বরাদ্দ না করা অন্য একটি বিকল্প: একটি সিঙ্গলটন তৈরি করুন, শ্রেণীর বিষয়ে বলুন C, আপনার যেমন প্রয়োজন:

singleton<C>()

ব্যবহার

template <class X>
X& singleton()
{
    static X x;
    return x;
}

এটি বা ক্যাটলিনের উত্তর দুটিই বর্তমান সি ++ এ স্বয়ংক্রিয়ভাবে থ্রেড-নিরাপদ নয়, তবে সি ++ 0x এ থাকবে।


বর্তমানে জিসিসির অধীনে এটি থ্রেড নিরাপদ (এবং কিছুক্ষণের জন্য হয়েছে)।
মার্টিন ইয়র্ক

13
এই ডিজাইনের সমস্যাটি হ'ল যদি একাধিক লাইব্রেরি জুড়ে ব্যবহার করা হয়। প্রতিটি লাইব্রেরির সিঙ্গলটনের নিজস্ব অনুলিপি রয়েছে যা গ্রন্থাগারটি ব্যবহার করে। সুতরাং এটি আর সিঙ্গলটন নয়।
মার্টিন ইয়র্ক

6

আমি উত্তরের মধ্যে সিআরটিপি বাস্তবায়ন পাইনি, সুতরাং এটি এখানে:

template<typename HeirT>
class Singleton
{
public:
    Singleton() = delete;

    Singleton(const Singleton &) = delete;

    Singleton &operator=(const Singleton &) = delete;

    static HeirT &instance()
    {
        static HeirT instance;
        return instance;
    }
};

এটি থেকে আপনার শ্রেণীর উত্তরাধিকারী ব্যবহার করতে, যেমন: class Test : public Singleton<Test>


1
আমি ডিফল্ট কনস্ট্রাক্টর সুরক্ষিত এবং '= ডিফল্ট;' না করা পর্যন্ত এটি সি ++ 17 এর সাথে কাজ করতে পারা যায় না।
WFranczyk

6

গৃহীত উত্তরের সমাধানটির একটি উল্লেখযোগ্য ত্রুটি রয়েছে - নিয়ন্ত্রণটি main()ফাংশনটি ছাড়ার পরে সিঙ্গলটনের জন্য ডেস্ট্রাক্টরকে ডাকা হয় । সত্যিই সমস্যা হতে পারে, যখন কিছু নির্ভরশীল বস্তুগুলি ভিতরে বরাদ্দ করা হয় main

কিউটি অ্যাপ্লিকেশনটিতে একটি সিঙ্গলটন প্রবর্তনের চেষ্টা করার সময় আমি এই সমস্যার মুখোমুখি হয়েছি। আমি স্থির করেছিলাম, আমার সমস্ত সেটআপ ডায়লগ অবশ্যই সিঙ্গলটনের হতে হবে এবং উপরের প্যাটার্নটি গ্রহণ করবে। দুর্ভাগ্যক্রমে, Qt এর প্রধান বর্গটি ফাংশনে QApplicationস্ট্যাকের জন্য বরাদ্দ করা হয়েছিল mainএবং Qt কোনও ডায়ালগ তৈরি / ধ্বংস করতে নিষেধ করে যখন কোনও অ্যাপ্লিকেশন অবজেক্ট পাওয়া যায় না।

এজন্য আমি হ্যাপ-বরাদ্দকৃত সিলেটলেটগুলিকে পছন্দ করি। আমি সমস্ত সিলেটটনের জন্য একটি স্পষ্ট init()এবং term()পদ্ধতি সরবরাহ করি এবং তাদের ভিতরে কল করি main। এইভাবে সিঙ্গেলটন তৈরি / ধ্বংসের ক্রমটির উপরে আমার সম্পূর্ণ নিয়ন্ত্রণ রয়েছে এবং আমি গ্যারান্টিও দিচ্ছি যে সিলেটলেটন তৈরি করা হবে, কেউ ফোন করুক getInstance()বা না করুক না কেন ।


2
আপনি যদি বর্তমানে গৃহীত উত্তরটি উল্লেখ করছেন তবে আপনার প্রথম বক্তব্যটি ভুল। সমস্ত স্ট্যাটিক স্টোরেজ সময়কাল অবজেক্টগুলি ধ্বংস না করা পর্যন্ত ডেস্ট্রাক্টরকে ডাকা হয় না।
মার্টিন ইয়র্ক

5

এখানে একটি সহজ বাস্তবায়ন।

#include <Windows.h>
#include <iostream>

using namespace std;


class SingletonClass {

public:
    static SingletonClass* getInstance() {

    return (!m_instanceSingleton) ?
        m_instanceSingleton = new SingletonClass : 
        m_instanceSingleton;
    }

private:
    // private constructor and destructor
    SingletonClass() { cout << "SingletonClass instance created!\n"; }
    ~SingletonClass() {}

    // private copy constructor and assignment operator
    SingletonClass(const SingletonClass&);
    SingletonClass& operator=(const SingletonClass&);

    static SingletonClass *m_instanceSingleton;
};

SingletonClass* SingletonClass::m_instanceSingleton = nullptr;



int main(int argc, const char * argv[]) {

    SingletonClass *singleton;
    singleton = singleton->getInstance();
    cout << singleton << endl;

    // Another object gets the reference of the first object!
    SingletonClass *anotherSingleton;
    anotherSingleton = anotherSingleton->getInstance();
    cout << anotherSingleton << endl;

    Sleep(5000);

    return 0;
}

কেবলমাত্র একটি অবজেক্ট তৈরি করা হয়েছে এবং প্রতিবছর পরেওয়ার্ডওয়ার্ডে এই বস্তুর রেফারেন্সটি ফিরে আসে।

SingletonClass instance created!
00915CB8
00915CB8

এখানে 00915CB8 হ'ল সিঙ্গেলটন অবজেক্টের মেমরি অবস্থানটি, প্রোগ্রামের সময়কালের জন্য একই তবে (সাধারণত!) প্রতিটি সময় প্রোগ্রামটি চালিত হওয়ার পরে আলাদা হয়।

এনবি এটি কোনও থ্রেড নিরাপদ নয় thread আপনাকে থ্রেড সুরক্ষা নিশ্চিত করতে হবে।


5

আপনি যদি গাদা বস্তুটি বরাদ্দ করতে চান তবে কেন একটি অনন্য পয়েন্টার ব্যবহার করবেন না। আমরা একটি অনন্য পয়েন্টার ব্যবহার করছি বলে মেমোরিটিও বাতিল করা হবে।

class S
{
    public:
        static S& getInstance()
        {
            if( m_s.get() == 0 )
            {
              m_s.reset( new S() );
            }
            return *m_s;
        }

    private:
        static std::unique_ptr<S> m_s;

        S();
        S(S const&);            // Don't Implement
        void operator=(S const&); // Don't implement
};

std::unique_ptr<S> S::m_s(0);

3
সি ++ 11 এ অবমূল্যায়িত। পরিবর্তে অনন্য_পিটার সুপারিশ করা হয়। cplusplus.com/references/mmory/auto_ptr cplusplus.com/references/memory/unique_ptr
অ্যান্ড্রু

2
এটি থ্রেড নিরাপদ নয়। ভাল করতে m_sএকটি স্থানীয় staticএর getInstance()এবং একটি পরীক্ষা ছাড়া অবিলম্বে এটি আরম্ভ।
গালিক

2

এটি সম্ভবত স্তূপ থেকে বরাদ্দ করা হয়েছে, তবে উত্সগুলি ছাড়া জানার উপায় নেই।

সাধারণ বাস্তবায়ন (ইতিমধ্যে ইমাসে থাকা কিছু কোড থেকে নেওয়া) হ'ল:

Singleton * Singleton::getInstance() {
    if (!instance) {
        instance = new Singleton();
    };
    return instance;
};

... এবং পরে পরিষ্কার করার জন্য কর্মক্ষেত্রের বাইরে চলে যাওয়ার উপর নির্ভর করুন।

আপনি যদি এমন প্ল্যাটফর্মে কাজ করেন যেখানে ম্যানুয়ালি ক্লিনআপ করতে হবে, আমি সম্ভবত একটি ম্যানুয়াল ক্লিনআপ রুটিন যুক্ত করব।

এইভাবে এটি করার সাথে আরেকটি সমস্যা হ'ল এটি থ্রেড-নিরাপদ নয়। একটি বহুবিবাহিত পরিবেশে, দুটি থ্রেড "যদি" এর মাধ্যমে উভয়ই নতুন উদাহরণ বরাদ্দ করার সুযোগ পাবে (সুতরাং উভয়ই হবে)। আপনি যদি যাইহোক পরিষ্কার করার জন্য প্রোগ্রামের সমাপ্তির উপর নির্ভর করে থাকেন তবে এটি এখনও কোনও চুক্তিতে খুব বেশি বড় নয়।


আপনি অনুমান করতে পারেন, যেহেতু আপনি দেখতে পাচ্ছেন যে উদাহরণটি পরিবর্তনশীল বর্গের উদাহরণের জন্য একটি পয়েন্টার।
আর্টেম বার্জার

3
গতিশীলভাবে সিঙ্গলটন বরাদ্দ করার প্রয়োজন নেই। প্রকৃতপক্ষে উপরের ডিজাইনটি ব্যবহার করে স্বয়ংক্রিয়ভাবে ডি-বরাদ্দ করার উপায় না হওয়ায় এটি একটি খারাপ ধারণা। এটিকে সুযোগ থেকে দূরে সরিয়ে দেওয়া যাক ডেস্ট্রাস্টারকে কল করে না এবং এটি কেবল অলস।
মার্টিন ইয়র্ক

অ্যাক্সিট ফাংশনটি ব্যবহার করে আপনি স্বয়ংক্রিয়ভাবে ডিলেট করতে পারেন। এটি আমরা যা করি (এটি একটি ভাল ধারণা বলে নয়)
জো

2

কেউ উল্লেখ করেছেন std::call_onceএবং std::once_flag? ডাবল চেকড লকিং সহ - অন্যান্য বেশিরভাগ পন্থাগুলি নষ্ট হয়ে গেছে।

সিঙ্গলটন প্যাটার্ন বাস্তবায়নের একটি বড় সমস্যা হ'ল নিরাপদ সূচনা। একমাত্র নিরাপদ উপায় হ'ল বাধা সিঙ্ক্রোনাইজ করার সাথে সূচনা ক্রমটি রক্ষা করা। তবে সেই বাধাগুলি নিজেরাই নিরাপদে শুরু করা দরকার। std::once_flagগ্যারান্টিযুক্ত নিরাপদ সূচনা পাওয়ার ব্যবস্থাটি।


2

আমরা সম্প্রতি আমার EECS ক্লাসে এই বিষয়টি নিয়েছি। আপনি যদি বক্তৃতার নোটগুলি বিস্তারিতভাবে দেখতে চান তবে দেখুন http://umich.edu/~eecs381/lecture/IdiomsDesPattsCreational.pdf

দুটি উপায় আছে যা আমি একটি সিঙ্গলটন ক্লাসটি সঠিকভাবে তৈরি করতে জানি।

প্রথম উপায়:

আপনার উদাহরণটিতে এটি যেমন রয়েছে তেমনই এটি বাস্তবায়ন করুন। ধ্বংস হিসাবে, "সিঙ্গেলটন সাধারণত প্রোগ্রামটি চালুর দৈর্ঘ্যের জন্য সহ্য করে; কোনও প্রোগ্রাম শেষ হয়ে গেলে বেশিরভাগ ওএস মেমরি এবং অন্যান্য সংস্থানগুলি পুনরুদ্ধার করতে পারে, সুতরাং এই সম্পর্কে উদ্বিগ্ন না হওয়ার পক্ষে যুক্তি রয়েছে" "

তবে প্রোগ্রাম সমাপ্তির সময় পরিষ্কার করা ভাল অনুশীলন। অতএব, আপনি একটি সহায়ক স্ট্যাটিক সিঙ্গলটনডাস্ট্রিক্ট ক্লাসের সাথে এটি করতে পারেন এবং এটি আপনার সিঙ্গেলনে বন্ধু হিসাবে ঘোষণা করতে পারেন।

class Singleton {
public:
  static Singleton* get_instance();

  // disable copy/move -- this is a Singleton
  Singleton(const Singleton&) = delete;
  Singleton(Singleton&&) = delete;
  Singleton& operator=(const Singleton&) = delete;
  Singleton& operator=(Singleton&&) = delete;

  friend class Singleton_destroyer;

private:
  Singleton();  // no one else can create one
  ~Singleton(); // prevent accidental deletion

  static Singleton* ptr;
};

// auxiliary static object for destroying the memory of Singleton
class Singleton_destroyer {
public:
  ~Singleton_destroyer { delete Singleton::ptr; }
};

সিঙ্গেলটন_ডেস্ট্রোয়ার প্রোগ্রাম স্টার্টআপে তৈরি করা হবে এবং "প্রোগ্রামটি শেষ হয়ে গেলে সমস্ত গ্লোবাল / স্ট্যাটিক অবজেক্ট রানটাইম লাইব্রেরি শাটডাউন কোড (লিংক দ্বারা সন্নিবেশিত) দ্বারা ধ্বংস করা হয়, তাই_ডেস্ট্রোয়ার ধ্বংস হয়ে যাবে; এর ডেস্ট্রাক্টর সিঙ্গলটন মুছে ফেলবে, এটি চালিয়ে যাবে বিনাশকারী। "

দ্বিতীয় উপায়

এটিকে মিঃ সিঙ্গেলটন বলা হয়, এটি সি ++ উইজার্ড স্কট মায়ার্স দ্বারা নির্মিত। সহজভাবে get_instance () আলাদাভাবে সংজ্ঞায়িত করুন। এখন আপনি পয়েন্টার সদস্য ভেরিয়েবল থেকেও মুক্তি পেতে পারেন।

// public member function
static Singleton& Singleton::get_instance()
{
  static Singleton s;
  return s;
}

কারণ ফিরে মান রেফারেন্স দ্বারা হয় এবং আপনি ব্যবহার করতে পারেন এই ঝরঝরে .পরিবর্তে সিনট্যাক্স ->এক্সেস সদস্য ভেরিয়েবল করতে।

"সংকলক স্বয়ংক্রিয়ভাবে কোড তৈরি করে যা ঘোষণার মাধ্যমে প্রথমবার তৈরি করে, তারপরে নয়, এবং তারপরে প্রোগ্রাম সমাপ্তিতে স্থির বস্তুটিকে মুছে দেয়" "

এটিও নোট করুন যে মায়ার্স সিঙ্গলটনের সাহায্যে আপনি "খুব কঠিন পরিস্থিতিতে পড়তে পারেন যদি সমাপ্তির সময় অবজেক্টগুলি একে অপরের উপর নির্ভর করে - যখন সিঙ্গেলটন অন্যান্য বস্তুর সাথে তুলনামূলকভাবে অদৃশ্য হয়ে যায়? তবে সাধারণ অ্যাপ্লিকেশনগুলির জন্য, এটি দুর্দান্ত কাজ করে।"


1

এখানে অন্যান্য আলোচনার পাশাপাশি, এটি লক্ষণীয় যে আপনার গ্লোবাল-নেস থাকতে পারে, এক নজরে ব্যবহার সীমাবদ্ধ না করে। উদাহরণস্বরূপ, কিছু উল্লেখের ক্ষেত্রে বিবেচনা করুন ...

struct Store{
   std::array<Something, 1024> data;
   size_t get(size_t idx){ /* ... */ }
   void incr_ref(size_t idx){ /* ... */}
   void decr_ref(size_t idx){ /* ... */}
};

template<Store* store_p>
struct ItemRef{
   size_t idx;
   auto get(){ return store_p->get(idx); };
   ItemRef() { store_p->incr_ref(idx); };
   ~ItemRef() { store_p->decr_ref(idx); };
};

Store store1_g;
Store store2_g; // we don't restrict the number of global Store instances

এখন কোনও ফাংশনের অভ্যন্তরে কোথাও (যেমন main) আপনি করতে পারেন:

auto ref1_a = ItemRef<&store1_g>(101);
auto ref2_a = ItemRef<&store2_g>(201); 

রেফগুলিকে তাদের নিজ নিজ কাছে কোনও পয়েন্টার সংরক্ষণের প্রয়োজন হয় না Storeকারণ তথ্যটি সংকলন-সময়ে সরবরাহ করা হয়। আপনার Storeজীবনকাল সম্পর্কে আপনাকেও চিন্তা করতে হবে না কারণ সংকলকটির প্রয়োজন এটি বিশ্বব্যাপী। যদি সত্যিই কেবলমাত্র একটি উদাহরণ থাকে Storeতবে এই পদ্ধতির কোনও ওভারহেড নেই; একাধিক উদাহরণ সহ এটি কোড জেনারেশন সম্পর্কে চালাক হতে সংকলকটির উপর নির্ভর করে। যদি প্রয়োজন হয় তাহলে, ItemRefবর্গ এমনকি একটি তৈরি করা যেতে পারে friendএর Store(আপনি টেমপ্লেট করা থাকতে পারে বন্ধুদের!)।

যদি Storeনিজেই একটি টেম্প্লেটেড শ্রেণি হয় তবে জিনিসগুলি মেসেজার হয়ে যায় তবে নীচের স্বাক্ষর সহ কোনও সহায়ক শ্রেণি প্রয়োগ করে সম্ভবত এই পদ্ধতিটি ব্যবহার করা সম্ভব:

template <typename Store_t, Store_t* store_p>
struct StoreWrapper{ /* stuff to access store_p, e.g. methods returning 
                       instances of ItemRef<Store_t, store_p>. */ };

ব্যবহারকারী এখন StoreWrapperপ্রতিটি বৈশ্বিক Storeউদাহরণের জন্য একটি প্রকার (এবং গ্লোবাল উদাহরণ) তৈরি করতে পারে এবং সর্বদা স্টোরগুলিকে তাদের মোড়কের উদাহরণের মাধ্যমে অ্যাক্সেস করতে পারে (এইভাবে ব্যবহারের জন্য প্রয়োজনীয় টেম্পলেট প্যারামিটারগুলির বিশ্রী বিবরণটি ভুলে যায় Store)।


0

এটি অবজেক্ট লাইফ-টাইম ম্যানেজমেন্ট সম্পর্কে। ধরুন আপনার সফ্টওয়্যারটিতে সিঙ্গেলটনের চেয়েও বেশি কিছু আছে এবং তারা লগার সিঙ্গলটনের উপর নির্ভর করে। অ্যাপ্লিকেশন ধ্বংসের সময়, ধরুন অন্য কোনও সিঙ্গলটন অবজেক্ট লগার তার ধ্বংসের পদক্ষেপগুলিতে লগ করতে ব্যবহার করে। আপনাকে গ্যারান্টি দিতে হবে যে শেষ পর্যন্ত লগার পরিষ্কার করা উচিত। অতএব, দয়া করে এই কাগজটিও দেখুন: http://www.cs.wustl.edu/~schmidt/PDF/ObjMan.pdf


0

আমার বাস্তবায়ন গালিকের মতো। পার্থক্যটি হ'ল আমার প্রয়োগটি ভাগ করা পয়েন্টারগুলিকে বরাদ্দ মেমরি পরিষ্কার করার অনুমতি দেয়, যতক্ষণ না অ্যাপ্লিকেশনটি বের হয় এবং স্ট্যাটিক পয়েন্টারগুলি পরিষ্কার না হওয়া পর্যন্ত মেমরিটিকে ধরে রাখার বিপরীতে।

#pragma once

#include <memory>

template<typename T>
class Singleton
{
private:
  static std::weak_ptr<T> _singleton;
public:
  static std::shared_ptr<T> singleton()
  {
    std::shared_ptr<T> singleton = _singleton.lock();
    if (!singleton) 
    {
      singleton.reset(new T());
      _singleton = singleton;
    }

    return singleton;
  }
};

template<typename T>
std::weak_ptr<T> Singleton<T>::_singleton;

0

আপনার কোডটি সঠিক, আপনি ক্লাসের বাইরে উদাহরণ পয়েন্টার হিসাবে ঘোষণা করেন নি । স্ট্যাটিক ভেরিয়েবলের অভ্যন্তর শ্রেণীর ঘোষণাগুলি সি ++ এ ঘোষণা হিসাবে বিবেচিত হয় না, তবে এটি সি # বা জাভা ইত্যাদির মতো অন্যান্য ভাষায় অনুমোদিত is

class Singleton
{
   public:
       static Singleton* getInstance( );
   private:
       Singleton( );
       static Singleton* instance;
};
Singleton* Singleton::instance; //we need to declare outside because static variables are global

আপনি অবশ্যই জানেন যে সিঙ্গলটন উদাহরণটি আমাদের দ্বারা ম্যানুয়ালি মুছে ফেলার দরকার নেই । আমাদের পুরো প্রোগ্রাম জুড়ে এটির একটি একক অবজেক্টের প্রয়োজন, সুতরাং প্রোগ্রাম কার্যকর হওয়ার শেষে, এটি স্বয়ংক্রিয়ভাবে বাতিল হয়ে যাবে।


-1

উপরের সাথে সংযুক্ত কাগজটি ডাবল চেকড লকিংয়ের ঘাটতি বর্ণনা করে যে কম্পাইলারটি অবজেক্টটির জন্য মেমরি বরাদ্দ করতে পারে এবং বরাদ্দকৃত মেমরির ঠিকানায় একটি পয়েন্টার সেট করতে পারে, অবজেক্টের কনস্ট্রাক্টর বলার আগেই। সি ++ এ ম্যানুয়ালি ম্যানুয়ালি বরাদ্দ করতে বরাদ্দ ব্যবহার করা, এবং তারপরে মেমরিটি আরম্ভ করার জন্য কনস্ট্রাক্ট কল ব্যবহার করা বেশ সহজ। এই কৌশলটি ব্যবহার করে, ডাবল-চেক করা লকিং ঠিক কাজ করে।


2
দুর্ভাগ্যবশত না. এটি সর্বোত্তম সি ++ বিকাশকারীরা সেখানকার বেশ কয়েকটি গভীরতার সাথে আলোচনা করেছেন। ডাবল চেকড লকিং সি ++ 03 এ ভাঙ্গা।
মার্টিন ইয়র্ক

-1
#define INS(c) private:void operator=(c const&){};public:static c& I(){static c _instance;return _instance;}

উদাহরণ:

   class CCtrl
    {
    private:
        CCtrl(void);
        virtual ~CCtrl(void);

    public:
        INS(CCtrl);

-1

সাধারণ সিঙ্গলটন ক্লাস, এটি আপনার শিরোনাম শ্রেণীর ফাইল হতে হবে

#ifndef SC_SINGLETON_CLASS_H
#define SC_SINGLETON_CLASS_H

class SingletonClass
{
    public:
        static SingletonClass* Instance()
        {
           static SingletonClass* instance = new SingletonClass();
           return instance;
        }

        void Relocate(int X, int Y, int Z);

    private:
        SingletonClass();
        ~SingletonClass();
};

#define sSingletonClass SingletonClass::Instance()

#endif

আপনার সিঙ্গলটনে এটির মতো অ্যাক্সেস করুন:

sSingletonClass->Relocate(1, 2, 5);

-3

আমার মনে হয় আপনার একটি স্ট্যাটিক ফাংশন লেখা উচিত যাতে আপনার স্ট্যাটিক অবজেক্ট মুছে ফেলা হয়। আপনি যখন আপনার অ্যাপ্লিকেশনটি বন্ধ করতে চলেছেন তখন আপনার এই ফাংশনটি কল করা উচিত। এটি নিশ্চিত করবে যে আপনার মেমরি ফাঁস করবেন না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.