c++ - 在程序启动时自动执行代码而不违反 ODR
问题描述
我尝试编写一种简单的方法来在程序启动时自动执行代码(不使用不可移植的属性())。
我写了下面的代码,我问如果在 main() 之前编写的代码放在头文件中,它是否违反了 ODR。或者,内联函数和变量会阻止这种情况吗?如果违反 ODR,是否会出现两次调用该函数的情况?
#include <iostream>
//-----
template <void(*init_function)()>
class execute_at_start
{
struct dummy final {};
~execute_at_start() = delete;
inline static dummy execute_() { init_function(); return dummy{}; }
inline static dummy auto_init_ = execute_();
};
//-----
inline void echo(){ std::cout << "echo" << std::endl; }
template class execute_at_start<&echo>;
int main()
{
std::cout << "EXIT SUCCESS" << std::endl;
return EXIT_SUCCESS;
}
先感谢您
解决方案
您的解决方案应该是 ODR 安全的。auto_init_
C++ 标准要求类模板的每个不同实例化只有一个静态数据成员实例,execute_at_start<>
并且它被初始化一次。
Itanium C++ ABI(大多数编译器都遵守它,除了 MSVC)需要全局变量的保护变量(auto_init_
此处)以确保它们被初始化一次:
如果函数范围的静态变量或具有模糊链接的静态数据成员(即类模板的静态数据成员)被动态初始化,则有一个关联的保护变量用于保证构造只发生一次。
有关更多详细信息,请参阅Itanium C++ ABI §2.8 初始化保护变量。
另一个不依赖保护变量的标准 ODR 安全解决方案是Schwarz Counter。std::cout
自 C++ 出现以来,它就被用于初始化标准流(和朋友)。在这个解决方案counter
中是一个具有外部链接的显式保护变量,它确保只有第一次调用execute_at_start
构造函数调用init_function
:
// Header begin.
#include <iostream>
template<void(*init_function)()>
class execute_at_start {
static inline int counter = 0;
public:
execute_at_start() {
if(!counter++)
init_function();
}
};
inline void echo() { std::cout << "echo" << std::endl; }
execute_at_start<echo> const execute_at_start_echo; // A copy in each translation unit.
// Header end.
int main() {}
推荐阅读
- javascript - 如何正确读取 NextJS 中的 Axios 授权令牌以获取需要身份验证的请求?
- azure - 如何在 azure 数据工厂中获取更新记录之前和之后
- javascript - 针对具有相同类 jquery 的特定元素
- php - 在 PHP 中使用嵌套的 foreach 循环
- python - processpoolexecutor 子进程突然停止
- ios - 免费试用 IAP + 非续订 IAP
- flutter - 除了颤动中的 listview.builder() 之外,还有其他方法可以遍历列表并在 build() 中构建小部件吗?
- node.js - 使用 npm node-csv 和 csvtojson 时 nodejs 中的未知文件扩展名“.csv”
- sql-server - 如何并行运行 SQL Server 存储过程的多个实例
- android - 如何在活动之间共享 ViewModelProvider.Factory 实例