c++ - প্রোগ্রামিং সি++




সি++ একক নকশা নকশা প্যাটার্ন (12)

আপনি বস্তু বরাদ্দ বরাদ্দ করতে চান, কেন একটি অনন্য পয়েন্টার ব্যবহার করবেন না। আমরা একটি অনন্য পয়েন্টার ব্যবহার করা হয়, কারণ মেমরি এছাড়াও deallocated করা হবে।

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);

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

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

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

আমার প্রধান প্রশ্ন হচ্ছে, আমি কিভাবে সঠিকভাবে এটিকে বাস্তবায়ন করব?


আপনি মেমরি বরাদ্দ এড়াতে পারে। বহু রূপ আছে, সব multithreading পরিবেশ ক্ষেত্রে সমস্যা হচ্ছে।

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

class Singleton
{
private:
   Singleton();

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

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


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


আরেকটি অ-বরাদ্দকরণ বিকল্প: ক্লাস C একটি সিঙ্গলটন তৈরি করুন, যেমনটি আপনার দরকার:

singleton<C>()

ব্যবহার

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

এই বা না Catalin এর উত্তর স্বয়ংক্রিয় C ++ এ স্বয়ংক্রিয়ভাবে থ্রেড-নিরাপদ, তবে সি ++ 0x এ হবে।


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


একটি সিঙ্গলটন হচ্ছে, আপনি সাধারণত এটি ধ্বংস করতে চান না।

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


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

#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 হল সিঙ্গলটন অবজেক্টের মেমরি অবস্থান, প্রোগ্রামের সময়কালের জন্য একই রকম তবে প্রোগ্রামটি চলাকালীন প্রতিটি সময় (সাধারণত!) আলাদা।

NB এটি একটি থ্রেড নিরাপদ নয়। আপনাকে থ্রেড নিরাপত্তা নিশ্চিত করতে হবে।


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

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

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

... এবং পরে পরিষ্কার করার সুযোগ সুযোগ যাচ্ছে প্রোগ্রাম উপর নির্ভর।

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

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


কেউ কি std::call_once এবং std::once_flag উল্লেখ std::once_flag ? সর্বাধিক অন্যান্য পদ্ধতির - ডবল চেক লকিং সহ - ভাঙ্গা হয়।

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


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

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

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


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

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

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
};

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

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

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

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

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


@ লকী আস্তারের উত্তর চমৎকার।

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

এই ক্ষেত্রে std::shared_ptr ব্যবহার করা যেতে পারে std::shared_ptr সব ব্যবহারকারীদের জন্য জীবিত রাখতে এমনকি যখন স্ট্যাটিক ধ্বংসকারীরা প্রোগ্রামের শেষে ডাকা হচ্ছে:

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() {}
};






singleton