在不违反 ODR 的情况下在程序启动时自动执行代码
Executing code automatically at program start without violating ODR
我尝试编写一种简单的方法来在程序启动时自动执行代码(不使用 not portable attribute())。
我写了下面的代码,我想问的是,如果在 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 安全的。 C++ 标准要求对于 execute_at_start<>
class 模板的每个不同实例只有一个静态数据成员实例 auto_init_
并且它被初始化一次。
Itanium C++ ABI(大多数编译器都遵守它,MSVC 除外)需要全局变量的保护变量(auto_init_
此处)以确保它们被初始化一次:
If a function-scope static variable or a static data member with vague linkage (i.e., a static data member of a class template) is dynamically initialized, then there is an associated guard variable which is used to guarantee that construction occurs only once.
有关详细信息,请参阅 Itanium C++ ABI §2.8 Initialization Guard Variables。
针对此问题的另一个不依赖保护变量的标准 ODR 安全解决方案是 Schwarz Counter。自 C++ 诞生以来,它就被用于初始化标准流(std::cout
和朋友们)。在此解决方案中,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() {}
我尝试编写一种简单的方法来在程序启动时自动执行代码(不使用 not portable attribute())。
我写了下面的代码,我想问的是,如果在 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 安全的。 C++ 标准要求对于 execute_at_start<>
class 模板的每个不同实例只有一个静态数据成员实例 auto_init_
并且它被初始化一次。
Itanium C++ ABI(大多数编译器都遵守它,MSVC 除外)需要全局变量的保护变量(auto_init_
此处)以确保它们被初始化一次:
If a function-scope static variable or a static data member with vague linkage (i.e., a static data member of a class template) is dynamically initialized, then there is an associated guard variable which is used to guarantee that construction occurs only once.
有关详细信息,请参阅 Itanium C++ ABI §2.8 Initialization Guard Variables。
针对此问题的另一个不依赖保护变量的标准 ODR 安全解决方案是 Schwarz Counter。自 C++ 诞生以来,它就被用于初始化标准流(std::cout
和朋友们)。在此解决方案中,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() {}