- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 init_seg
来控制三个 C++ 类对象的创建。每个对象都在不同的源文件/翻译单元中。调试显示在 CRT 初始化期间正在按预期创建对象。
对象正在按照其源文件的字母顺序进行初始化。我想更改它,因为它不太正确。我在 init_seg
上访问了 MSDN 的页面, 并说明用途是:
#pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )
看来 lib
和 section-name
的使用是互斥的,所以我不清楚如何使用 init_seg(lib)
并提供部分/组名称以获得正确的字母顺序。
当我尝试使用按字母顺序排列的字符串来控制顺序时:
#pragma init_seg(lib, "01")
它会导致警告,我猜这意味着事情不会按预期工作:
warning C4081: expected ')'; found ','
当我尝试直接使用 ".CRT$XCB"
、".CRT$001"
和 ".CRT 直接插入 CRT 启动代码时$XCB001"
(以及其他使用字母顺序的变体):
#pragma init_seg(".CRT$XCB")
它会导致另一个警告,我猜这意味着事情不会按预期工作:
warning C4075: initializers put in unrecognized initialization area
我在 Stack Overflow 上发现了一个关于它的问题,但是 answer was a guess并且它不涵盖多个翻译单元。我还找到了 KB104248 的存档在 Wayback Machine 上,但它也没有太大帮助,因为它只显示了 compiler
、lib
和 user
的使用。
所以我的问题是,如何利用 init_seg
来控制三个不同源文件中三个对象的精确创建顺序?
最佳答案
以下是我在 XP 和 VS2002/VS2003、Vista 和 VS2005/VS2008、Windows 7 和 VS2008/VS2010、Windows 8 和 VS2010/VS2012/VS2013 以及使用 VS2015 的 Windows 10 上进行测试后发现的结果。 #pragma_init(<name>)
从 VC++ 1.0 天开始就可用。 MS 没有发布太多关于它的信息,但我们知道它来自 VC++1.0 (archived KB104248) 的文档。通过VS2017 .
#pragma init_seg(lib)
几乎是完美的。但是,对象文件在 VS2008 及更早版本中按字母顺序排列,因此初始化顺序为 a-b-c
(不需要的)而不是 c-b-a
(期望)。它在 VS2010 及更高版本上没问题。不明显的是订单的布局恰好为 c-b-a
在vcproj
文件。
#pragma init_seg(".CRT$XCB-0NN")
似乎工作。我们的std::strings
STRING_A
和 STRING_B
很早就创建了(并且对象的顺序正确),但是 STRING_B
导致 suhutdown 崩溃。地址是0x0000000d
, 它出现了 std::string
(及其 vtable)过早销毁。
#pragma init_seg(".CRT$XCU-0NN")
在启动和关闭期间按预期工作。如果我正确解析了我阅读的内容,那么 U
在组名XCU
指示用户定义的对象。这意味着我们的对象是在 #pragma init_seg(lib)
之间的某处创建的和 #pragma init_seg(user)
提供。
下面是如何从源文件中初始化一个对象 C,然后是一个对象 B,然后是一个对象 A a.cpp
, b.cpp
和 c.cpp
.
源文件 a.cpp
:
class A
{
...
};
#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-030")
A a; // created 3rd
#pragma warning(default: 4075)
源文件 b.cpp
:
class B
{
...
};
#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-020")
const B b; // created 2nd
#pragma warning(default: 4075)
源文件 c.cpp
:
#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-010")
const std::string c; // created 1st
const std::string d; // created 1st
#pragma warning(default: 4075)
我们的用例是创建三个只读对象并避免 C++ 的 static initialization order fiasco 问题。和微软的 thread local storage .
该技术避免了在 C++03 中缺少 C++ 动态初始化程序。它还解决了微软无法提供 C++11 的 Dynamic Initialization and Destruction with Concurrency 的问题。 (或者更准确地说,微软 10 年来未能提供核心语言功能)。
这里是对 Thread Local Storage (TLS) 问题的引用在 MSDN 上:
On Windows operating systems before Windows Vista, __declspec( thread ) has some limitations. If a DLL declares any data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded. After the DLL is loaded with LoadLibrary, it causes system failure whenever the code references the __declspec( thread ) data. Because the global variable space for a thread is allocated at run time, the size of this space is based on a calculation of the requirements of the application plus the requirements of all the DLLs that are statically linked. When you use LoadLibrary, you cannot extend this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your DLL to allocate TLS if the DLL might be loaded with LoadLibrary.
还值得一提的是,似乎对部分或组名称中的字符数有限制。存档KB 104248使用名称 "user_defined_segment_name"
26 个字符。
关于c++ - 使用 init_seg 时如何为三个 C++ 对象命名部分/组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42895755/
我试图确保程序首先调用函数以确保关键对象的初始化。但是,我对如何使用/调用 init_seg 感到困惑。 例如,从 msdn 的文档来看,似乎首先调用的是以下内容。 #pragma init_seg(
我正在使用 init_seg 来控制三个 C++ 类对象的创建。每个对象都在不同的源文件/翻译单元中。调试显示在 CRT 初始化期间正在按预期创建对象。 对象正在按照其源文件的字母顺序进行初始化。我想
我是一名优秀的程序员,十分优秀!