如何在C ++中保存对Singleton的get_instance调用?

时间:2017-11-06 21:07:50

标签: c++ singleton embedded

在下面的虚拟示例中,我想创建一个Singleton,我可以保存get_instance调用,这对嵌入式微控制器来说代价很高。

#include <stdio.h>

template<class T>
class CamelBase {
    public:
    static T& get_instance() {
        static T instance;
        return instance;
    }    

    protected:
    CamelBase() {}    
    CamelBase(T const&) = delete;
    void operator=(T const&) = delete;
};

class Camel: public CamelBase<Camel> {
    public:
    int answer() {
        return 42;
    }
};

int main(void)
{
    printf("%d\n", Camel::get_instance().answer());
    return Camel::get_instance().answer();
}

我们可以在https://godbolt.org/g/1ugPxx看到每次调用answer都会调用get_instance,这很奇怪,因为编译器无论如何都会内联answer

main:
  push {r4, lr}
  bl CamelBase<Camel>::get_instance()
  mov r1, #42
  ldr r0, .L15
  bl printf
  bl CamelBase<Camel>::get_instance()
  pop {r4, lr}
  mov r0, #42
  bx lr

是否有另一种方法可以为I2C或SPI等外设编写那种Singleton?

使用静态类更好吗?引用指针?

3 个答案:

答案 0 :(得分:2)

每次编写一个函数静态变量时,都会转换为条件:如果它尚未初始化,它将是。您的编译器可能无法全局优化,因此它不知道实例是否已存在,因此调用。

你应该问自己的第一个问题:它真的是一个单身人士吗?如果您有多个实例(即使在测试时),单例模式文档表明某些内容将超出可恢复性。是你的情况吗?如果没有,您只需要一个公共实例,请使用静态变量(除非您需要特定的销毁订单)。请记住,单例会在代码中记录设计缺陷,而不是作为功能。

如果你真的需要一个单例,我们通常拥有的是(与上面相反,这是Scott Meyers singleton)一个指向实例的静态私有成员指针(默认为nullptr)和一个显式的if in如果需要,get_instance()填充它。您的编译器可能会或可能不会比另一个更好地优化它 - 通常它不会在同一个fn中检查两次条件,并且get_instance()将被内联。

如果这没有帮助,你仍然可以为单身人士提供每个功能的参考,比如auto&& instance = CamelBase<Camel>::get_instance()。但是,你可以将它作为一个函数参数,然后问题就会出现,直到main - 你只需创建一个实例。如果您想要按需实例,这不起作用。

答案 1 :(得分:1)

据我所知,构建static T instance会阻止内联。如果你使用类似的东西:

private:
    static T inst;
public:
static T& get_instance() {
    static T *instance = &inst;
    return *instance;
}    

然后get_instance()被内联;

答案 2 :(得分:0)

您可以在单独的变量中为实例提供引用

E.g。

Camel& camel = Camel::get_instance();
std::cout << camel.answer();