如何在main()获得控制之前编写要执行的代码

  • 本文关键字:执行 代码 控制 main c++
  • 更新时间 :
  • 英文 :


我正在将一个类移植到C++,并且需要在创建类的第一个实例之前执行一些初始化代码;在main()获得控制之前执行代码很适合我。如何在C++中执行?

初始答案

您可以在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进行队列,则它不工作。

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 的全局实例

我的答案解决了您真正的问题——在类的第一个实例之前执行一次性初始化,而不是在main之前执行。

只需使用一个静态变量来确保一次性init代码只执行一次。如果您需要线程安全,请使用同步,尽管它会影响性能。

class MyClass {
    MyClass() {
         // Perform the one-time initialization.
         static bool passed = false;
         if (!passed) {
             performOneTimeInitialization();
             passed = true;
         }
         // Continue with normal construction.
    }
};

实际问题的附加解决方案(使用工厂方法):

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,将预初始化考虑到自己的类中只是一个更好的设计。

最新更新