我正在将一个类移植到 C++,并且需要在创建我的类的第一个实例之前执行一些初始化代码;在获得控制权之前执行代码main()
适合我。如何在 C++ 中做到这一点?
6 回答
初步答案
namespace
您可以在范围内使用对象的构造函数。
namespace {
struct Init
{
Init()
{
// Initialization code here.
}
} init_;
} // namespace
请注意,这有一些限制,尤其是在 Windows 上。在 Windows 上,ctor 是在持有加载程序锁的情况下调用的,因此您无法执行任何需要加载 DLL 等的操作。这包括 WinSock 的初始化,因为它可以尝试加载外部 DLL。
更新
根据一些消息来源,您可以使用QueueUserAPC
. 这种技术也有局限性,尽管有所不同。我已经使用了它,我的实验表明,这仅在您使用 Visual Studio 及其 C 库作为DLL时才有效,即 MSVCRT.DLL、MSVCR100.DLL 等(/MD
或/MDd
开关)
更新 2
这是一个指向类似问题(实际上是我的)的链接,其中包含一个重要问题:
经过一些测试后,如果我从 DllMain() 将 APC 排队,似乎 APC 方法有效,但如果我从类的静态全局实例的 ctor 排队 APC,则它不起作用。
My answer addresses your real problem - performing one-time initialization before the first instance of your class, not executing before main.
Just use a static variable to make sure you execute the one time init code only once. Use synchronization if you need to be thread-safe, though it would have a performance hit.
class MyClass {
MyClass() {
// Perform the one-time initialization.
static bool passed = false;
if (!passed) {
performOneTimeInitialization();
passed = true;
}
// Continue with normal construction.
}
};
struct Init
{
Init()
{
/* Your Initialization Code */
}
} x;
int main()
{
}
全局和静态类是在 main() 开始执行之前构建的。
class hello {
hello () { std::cout << "hello" << std::endl; }
};
hello hi;
int main(){
std::cout << "hello again" << std::endl;
return 0;
}
输出将永远是
hello
hello again
因为 hello 对象实例是在 main 启动之前创建的,因为 hi 是类 hello 的全局实例
您实际问题的另一个解决方案(使用工厂方法):
namespace
{
struct Initializer
{
Initializer()
{
/* initializing code goes here */
}
}
}
MyClass CreateMyClass()
{
static Initializer init;
return new MyClass();
}
第一次调用 CreateMyClass 时会执行初始化代码。对于 C++11 编译器,它甚至应该是线程安全的。如果你没有并且需要线程安全,你可以检查 boost::call_once。
实际上,您在这里提出了两个不同的问题,一个描述了您要解决的问题:
我 [...] 需要在创建我的类的第一个实例之前执行一些初始化代码;
第二个是关于你认为问题可以如何解决的:
在 main() 获得控制权之前执行代码适合我。如何在 C++ 中做到这一点?
对于第二个问题,您已经多次获得一个答案(全局变量)。这可能是一个可行的解决方案,尽管我更喜欢私有静态类成员来限制该全局变量的可见性:
class X {
const static bool initialized;
};
//X.cpp:
namespace {
bool preInitialization() {
//your pre-main code here
return true;
}
}
bool X::initialized = preInitialization();
对于第一个问题,您可以延迟初始化代码的执行,直到您的类的第一个变量被初始化:
class X {
X();
};
//X.cpp:
namespace {
bool preInitialization() {
//your pre-main code here
return true;
}
}
X::X() {
static bool b = preInitialization();
}
这样,您的代码在 X 的第一次构造函数调用期间执行。这可能有一些缺点,例如,如果 X 的成员只能在初始化代码执行后进行初始化,或者在存在多个构造函数的情况下。您可以通过将其推入一个空的基类来改进该方法:
class PreInit {
static bool preInitialization() {
//your pre-main code here
return true;
}
public:
PreInit() {
static bool b =preInitialization();
}
};
class X : private PreInit {
//normal class implementation
};
这样,您甚至可以在第一次构造多个类的任何对象之前执行代码,只需从 PreInit 类派生所有有问题的类即可。将预初始化分解为自己的类,遵守 SRP,这只是一个更好的设计。