在下面的虚拟示例中,我想创建一个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?
使用静态类更好吗?引用指针?
答案 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();