반응형



#include <iostream>
#include <memory>
#include <mutex>

// ============================================================
//  Singleton: shared_ptr + weak_ptr 기반 수명 관리
//  - 외부 shared_ptr이 모두 소멸 → ref count=0 → 자동 소멸
//  - weak_ptr은 count에 영향 없음 (소유권 없는 관찰자)
// ============================================================
class Singleton {
public:
    Singleton(const Singleton&)            = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&)                 = delete;
    Singleton& operator=(Singleton&&)      = delete;

    // private 소멸자에 접근 가능한 custom deleter
    struct Deleter {
        void operator()(Singleton* p) const { delete p; }
    };

    static std::shared_ptr<Singleton> getInstance() {
        std::lock_guard<std::mutex> lock(mutex_);

        auto sp = instance_.lock();   // weak_ptr → shared_ptr 승격 시도
        if (!sp) {
            sp = std::shared_ptr<Singleton>(new Singleton(), Deleter{});
            instance_ = sp;           // weak_ptr 갱신 (count 영향 없음)
        }
        return sp;
    }

    void doSomething() const {
        std::cout << "  doSomething() called. value=" << value_ << "\n";
    }

    void setValue(int v) { value_ = v; }
    int  getValue() const { return value_; }

private:
    Singleton() : value_(0) {
        std::cout << "[+] Singleton constructed\n";
    }
    ~Singleton() {
        std::cout << "[-] Singleton destroyed\n";
    }

    static std::weak_ptr<Singleton> instance_;
    static std::mutex               mutex_;

    int value_;
};

std::weak_ptr<Singleton> Singleton::instance_;
std::mutex               Singleton::mutex_;


// ============================================================
//  전달 방식별 ref count 변화 확인용 함수들
// ============================================================

// 1) 값 전달 → 복사 → count+1
void byValue(std::shared_ptr<Singleton> sp) {
    std::cout << "  [byValue]    use_count=" << sp.use_count() << "\n";
}

// 2) const 참조 전달 → count 변화 없음
void byConstRef(const std::shared_ptr<Singleton>& sp) {
    std::cout << "  [byConstRef] use_count=" << sp.use_count() << "\n";
}

// 3) move 전달 → 소유권 이전, count 변화 없음, 원본 nullptr
void byMove(std::shared_ptr<Singleton> sp) {
    std::cout << "  [byMove]     use_count=" << sp.use_count()
              << "  (소유권 이전됨)\n";
}


int main() {
    std::cout << "=== 1. 기본 생성 및 소멸 ===\n";
    {
        auto s1 = Singleton::getInstance();          // count=1
        std::cout << "  s1 use_count=" << s1.use_count() << "\n";
        {
            auto s2 = Singleton::getInstance();      // count=2
            std::cout << "  s2 use_count=" << s2.use_count() << "\n";
        }   // s2 소멸 → count=1
        std::cout << "  s2 소멸 후 s1 use_count=" << s1.use_count() << "\n";
    }   // s1 소멸 → count=0 → ~Singleton() 호출

    std::cout << "\n=== 2. 소멸 후 재생성 ===\n";
    {
        auto s3 = Singleton::getInstance();          // 새로 생성
        s3->setValue(99);
        s3->doSomething();
    }   // 소멸

    std::cout << "\n=== 3. 값 전달 (count+1) ===\n";
    {
        auto s1 = Singleton::getInstance();          // count=1
        std::cout << "  호출 전 use_count=" << s1.use_count() << "\n";
        byValue(s1);                                 // 함수 내 count=2
        std::cout << "  호출 후 use_count=" << s1.use_count() << "\n"; // count=1
    }

    std::cout << "\n=== 4. const 참조 전달 (count 유지) ===\n";
    {
        auto s1 = Singleton::getInstance();
        std::cout << "  호출 전 use_count=" << s1.use_count() << "\n";
        byConstRef(s1);
        std::cout << "  호출 후 use_count=" << s1.use_count() << "\n";
    }

    std::cout << "\n=== 5. move 전달 (소유권 이전) ===\n";
    {
        auto s1 = Singleton::getInstance();
        std::cout << "  move 전 use_count=" << s1.use_count() << "\n";
        byMove(std::move(s1));                       // s1 → nullptr
        std::cout << "  move 후 s1 is nullptr? "
                  << (s1 == nullptr ? "YES" : "NO") << "\n";
    }   // byMove 내부 sp 소멸 → count=0 → ~Singleton()

    std::cout << "\n=== 6. 동일 인스턴스 확인 ===\n";
    {
        auto s1 = Singleton::getInstance();
        auto s2 = Singleton::getInstance();
        std::cout << "  same instance? "
                  << (s1.get() == s2.get() ? "YES" : "NO") << "\n";
        std::cout << "  use_count=" << s1.use_count() << "\n";
    }

    std::cout << "\n[main 종료]\n";
    return 0;
}



# C++17 이상 필요
g++ -std=c++17 -Wall -Wextra -o singleton main.cpp
./singleton

반응형