C++ 向量的Schwarz计数器
我正在看一个例子,在这个例子中,我需要保证一个全局静态std::vector在各种翻译单元中的某些静态对象之前被初始化(构造) 当我研究如何处理这个问题时,我遇到了两个建议的解决方案:C++ 向量的Schwarz计数器,c++,c++11,C++,C++11,我正在看一个例子,在这个例子中,我需要保证一个全局静态std::vector在各种翻译单元中的某些静态对象之前被初始化(构造) 当我研究如何处理这个问题时,我遇到了两个建议的解决方案: 在全局函数中使用静态对象来代替全局静态对象 施瓦兹计数器 我对使用Schwarz计数器的担心是std::vector将被初始化两次。从link中,我得到了“一种确保全局对象在第一次使用之前只初始化一次的有用技术,那就是保持使用它的翻译单元数量的计数。” 全局只初始化一次是如何工作的?根据我的推理,它将被初始化两次
请注意,在Schwarz计数器构造函数中初始化代码是什么样子的?我只能考虑使用新的布局。我只能说我过去是如何实现它的:我设计 一个特殊的“无操作”构造函数,它不执行任何操作,并使用 施瓦茨计数器中的新位置。比如:
class ForUseAsStatic
{
public:
enum MakeCtorNoop { makeCtorNoop };
ForUseAsStatic(); // normal ctor, called by Schwartz counter.
ForUseAsStatic( MakeCtorNoop );
// no-op constructor, used when
// defining the variable.
};
从形式上讲,这并不能保证编译器可以
在调用构造函数之前再次将内存设置为0,
但我从来没有听说过有这样的编译器
也可以在类中放置某种标志
自身,由构造函数测试。这只适用于
当然是静态对象(因为它在
工作指令)
另一种可能的技术(我在一些网站上看到过)
库)是为中的对象声明内存
汇编程序,或者如果编译器有某种方法
强制对齐。数据名通常不会损坏,因此
即使它是形式上未定义的行为,通常也会起作用。
(当然,对于标准库,库作者可以
请求编译器中的扩展,以帮助他们使用
问题。)
最后:今天,singleton习语或类似的东西被广泛使用
通常倾向于这种工作环境。这确实意味着你
必须编写myobj().xxx
,而不仅仅是myobj.xxx
,但是
一般认为这不是一个问题。您可以使用另一个间接级别:将全局变量作为指向向量的指针(将初始化为零),让您的计数器
新建向量,并将结果存储在指针中。我认为静态初始化问题没有正确答案。行为未定义,解决方案的选择取决于具体情况。这取决于:
- 编译器及其实现
- 大多数编译器在单个编译单元内提供保证
- 顺序可以由链接器决定,有时还受#pragma的影响
- 初始化可以在main开始执行之前的任何时间点进行
- 是否为具有静态变量的全局函数调用析构函数以及何时调用李>
- 应用程序架构
- 无论是否使用.DLL,某些环境都减少了对DLL中静态构造/销毁的管理支持,尤其是在加载需求时
- 无论应用程序是否是线程化的,这都会影响调用带有静态变量的全局函数的方式
最好的建议可能是通过另一种方式设计系统来避免这一惨败,尽管这可能不太实际。听起来您的应用程序不需要考虑一些关于可移植性的问题,而是针对具有特定编译器的特定环境
#pragma/编译器选项
您可能没有考虑的一个选项是,是否有一些编译器支持您所需要的内容
有关windows,请参阅:
对于g++:
启用init priority
并使用\uuuuu属性((init\u priority(n))
让Swartz计数器工作
一些示例忽略了一个对象,即空间只是为被分配的对象保留的,该对象被适当地对齐。这避免了您提到的构造之一。例如,在g++gnu中使用:
typedef char fake_istream[sizeof(istream)] __attribute__ ((aligned(__alignof__(istream))))
...
fake_istream cin;
为对象分配空间。该编译单元之外的所有代码都将该区域称为extern istream cin
(通过标题),并用一个新的字段初始化。应该注意确保漂亮的计数器是线程安全的(原子的)。相关:关于字节数组策略:在C++03中,您可以声明的大小总是超过在构造时对齐所需的大小,在C++11中,您有std::aligned\u storage::type
。这对于自定义类型来说很好,但是对于STL类型,比如std::vector,它如何工作呢?@Graznarak,它根本不工作。您可以尝试第二种可能性:声明原始内存,并依靠编译器不会将类型信息转换为变量名这一事实,或者您可以将STL类型封装在提供相同接口的类中。(这个类将包含一个指向STL类型的指针,并对其使用动态分配,以便能够准确地控制它的构造和破坏时间。)我想说这通常是个好主意,但我倾向于在嵌入式系统中工作,除非绝对必要,否则不赞成内存碎片和动态分配。“在编程中,没有一个问题不能通过添加另一个间接层来解决……接受删除一个间接层”