looyifan / Singleton

Created Wed, 02 Apr 2025 10:32:39 +0800 Modified Wed, 02 Apr 2025 16:37:48 +0800
467 Words

Apollo Singleton Macro

#ifndef CYBER_COMMON_MACROS_H_
#define CYBER_COMMON_MACROS_H_

#include <iostream>
#include <memory>
#include <mutex>
#include <type_traits>
#include <utility>

#include "cyber/base/macros.h"

DEFINE_TYPE_TRAIT(HasShutdown, Shutdown)

template <typename T>
typename std::enable_if<HasShutdown<T>::value>::type CallShutdown(T *instance) {
  instance->Shutdown();
}

template <typename T>
typename std::enable_if<!HasShutdown<T>::value>::type CallShutdown(
    T *instance) {
  (void)instance;
}

// There must be many copy-paste versions of these macros which are same
// things, undefine them to avoid conflict.
#undef UNUSED
#undef DISALLOW_COPY_AND_ASSIGN

#define UNUSED(param) (void)param

#define DISALLOW_COPY_AND_ASSIGN(classname) \
  classname(const classname &) = delete;    \
  classname &operator=(const classname &) = delete;

#define DECLARE_SINGLETON(classname)                                      \
public:                                                                  \
  static classname *Instance(bool create_if_needed = true) {              \
    static classname *instance = nullptr;                                 \
    if (!instance && create_if_needed) {                                  \
      static std::once_flag flag;                                         \
      std::call_once(flag,                                                \
                    [&] { instance = new (std::nothrow) classname(); }); \
    }                                                                     \
    return instance;                                                      \
  }                                                                       \
                                                                          \
  static void CleanUp() {                                                 \
    auto instance = Instance(false);                                      \
    if (instance != nullptr) {                                            \
      CallShutdown(instance);                                             \
    }                                                                     \
  }                                                                       \
                                                                          \
private:                                                                 \
  classname();                                                            \
  DISALLOW_COPY_AND_ASSIGN(classname)

#endif  // CYBER_COMMON_MACROS_H_

细节分析

  • 为了能够让程序员显式的禁用某个函数,C++11 标准引入了一个新特性:"=delete"函数。程序员只需在函数声明后上“=delete;”,就可将该函数禁用。

    class X3
    {
    public:
        X3();
        X3(const X3&) = delete;  // 声明拷贝构造函数为 deleted 函数
        X3& operator = (const X3 &) = delete; // 声明拷贝赋值操作符为 deleted 函数
    };
    
  • 在多线程编程中,有一个常见的情景是某个任务只需要执行一次。在C++11中提供了很方便的辅助类once_flag,call_once。

    #include <iostream>
    #include <thread>
    #include <mutex>
    
    std::once_flag flag;
    
    void do_once() {
        //也可以写在这里。要记住static,一旦flag被销毁了就不能保证只执行一次了
        //static std::once_flag flag;
        std::call_once(flag, [](){ std::cout << "Called once" << std::endl; });
    }
    
    int main() {
        std::thread t1(do_once);
        std::thread t2(do_once);
        std::thread t3(do_once);
        std::thread t4(do_once);
    
        t1.join();
        t2.join();
        t3.join();
        t4.join();
    }
    //可以看到,只会输出一行Called once