c – 使用什么而不是静态变量

c – 使用什么而不是静态变量,第1张

概述在C程序中,我需要一些辅助的常量对象,这些对象将被实例化一次,最好是在程序启动时.这些对象通常在同一个翻译单元中使用,因此最简单的方法是将它们设置为静态: static const Helper h(params); 但是有一个这个static initialization order问题,所以如果Helper引用其他一些静力学(通过参数),这可能会导致UB. 另一点是我最终可能需要在几个单元之间 在C程序中,我需要一些辅助的常量对象,这些对象将被实例化一次,最好是在程序启动时.这些对象通常在同一个翻译单元中使用,因此最简单的方法是将它们设置为静态:

static const Helper h(params);

但是有一个这个static initialization order问题,所以如果Helper引用其他一些静力学(通过参数),这可能会导致UB.

另一点是我最终可能需要在几个单元之间共享此对象.如果我只是将它保持静态并放入.h文件,那将导致多个对象.我可以通过使用extern等来避免这种情况,但这最终会引发相同的初始化顺序问题(而不是说它看起来非常C-ish).

我想过单身人士,但由于样板代码和不方便的语法(例如MySingleton :: GetInstance().MyVar),这将是过度杀伤 – 这些对象是助手,所以他们应该简化事情,而不是让它们复杂化……

同样的C FAQ mentions这个选项:

Fred& x() {   static Fred* ans = new Fred();   return *ans; }

这真的被使用并被认为是一件好事吗?我应该这样做,还是你会建议其他选择?谢谢.

编辑:我应该澄清为什么我真的需要帮助器:它们非常像常规常量,并且可以预先计算,但在运行时更方便.我宁愿在main之前实例化它们,因为它会自动解决多线程问题(在C 03中没有保护本地静态).另外,正如我所说,它们通常仅限于翻译单元,因此导出它们并在main()中初始化是没有意义的.您可以将它们视为常量,但仅在运行时已知.

解决方法 全球状态有多种可能性(无论是否可变).

如果您担心初始化问题,那么您应该使用本地静态方法来创建实例.

请注意,您提出的笨重的单件设计不是强制性设计:

class Singleton{public:  static voID DoSomething(int i)  {    Singleton& s = Instance();    // do something with i  }private:  Singleton() {}  ~Singleton() {}  static Singleton& Instance()  {    static Singleton S; // no dynamic allocation,it's unnecessary    return S;  }};// InvocationSingleton::DoSomething(i);

另一种设计有点类似,但我更喜欢它,因为它更容易转换到非全局设计.

class MonoID{public:  MonoID()  {    static State S;    state = &s;  }  voID doSomething(int i)  {    state->count += i;  }private:  struct State  {    int count;  };  State* state;};// UseMonoID m;m.doSomething(1);

这里的净优势是隐藏了国家的“全球性”,这是客户不必担心的实施细节.对缓存非常有用.

让我们,您,对设计提出疑问:

>你真的需要强制执行奇点吗?
>你真的需要在主要开始之前建造对象吗?

奇点通常过分强调. C 0x在这里会有所帮助,但即使这样,技术上强制执行奇点而不是依靠程序员来表现自己也会非常讨厌…例如在编写测试时:你真的想在每个单元测试之间卸载/重新加载程序改变每个之间的配置?啊.更简单的实例化它一次并对你的程序员也有信心…或功能测试;)

第二个问题是技术性的,而不是功能性的.如果您确实需要在程序入口点之前进行配置,那么您可以在启动时简单地阅读它.

这可能听起来很幼稚,但实际上在库加载期间计算存在一个问题:如何处理错误?如果抛出,则不加载库.如果你不扔,继续,你处于无效状态.不是很好笑,是吗?一旦真正的工作开始,事情就会简单得多,因为你可以使用常规的控制流逻辑.

如果你考虑测试状态是否有效……为什么不简单地在你测试的地方构建所有东西?

最后,global的问题在于引入了隐藏的依赖关系.当依赖关系隐含于推理执行流程或重构的影响时,情况要好得多.

编辑:

关于初始化顺序问题:保证单个翻译单元内的对象按其定义的顺序进行初始化.

因此,以下代码根据标准有效:

static int foo() { return std::numeric_limits<int>::max() / 2; }static int bar(int c) { return c*2; }static int const x = foo();static int const y = bar(x);

初始化顺序仅是引用另一个转换单元中定义的常量/变量时的问题.因此,静态对象可以自然地表达而没有问题,只要它们仅引用同一翻译单元内的静态对象即可.

关于空间问题:as-if规则可以在这里创造奇迹.非正式地,as-if规则意味着您指定一个行为并将其留给编译器/链接器/运行时来提供它,而无需在世界范围内如何提供它.这实际上是实现优化的.

因此,如果编译器链可以推断永远不会采用常量的地址,则它可能完全忽略常量.如果它可以推断出几个常量总是相等的,并且再次确认它们的地址永远不会被检查,它可以将它们合并在一起.

总结

以上是内存溢出为你收集整理的c – 使用什么而不是静态变量全部内容,希望文章能够帮你解决c – 使用什么而不是静态变量所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1213462.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存