【问题标题】:Is it good practice to hide Initialization code "before main"?在“main”之前隐藏初始化代码是一种好习惯吗?
【发布时间】:2015-10-27 17:46:44
【问题描述】:

我正在构建一个 c++ 库,我需要为我的程序(和其他默认资源对象)初始化一个 openGL 上下文。在 main 之前调用的代码块中“隐藏 Init.code”是否是一种好习惯(考虑到现代 c++ 语义)?我不能使用静态变量,因为我需要按特定顺序初始化事物! (我无法在 openGLm 或 SDL 之前初始化纹理!)

这是我的代码:

#include <stdio.h>

#ifdef _MSC_VER // For msvc / msvc++ 2015

#define CCALL __cdecl
#pragma section(".CRT$XCU",read)
#define INITIALIZER(f) \
   static void __cdecl f(void); \
   __declspec(allocate(".CRT$XCU")) void (__cdecl*f##_)(void) = f; \
   static void __cdecl f(void)

#elif defined(__GNUC__) for gcc / g++

#define CCALL
#define INITIALIZER(f) \
   static void f(void) __attribute__((constructor)); \
   static void f(void)

#endif

static void CCALL finalize(void)
{
    /* Some king of delete / dispose here : like SDL_Quit, ... */
}

INITIALIZER(initialize)
{
/* 
   HERE IS THE STARTUP CODE ...

*/

}

【问题讨论】:

  • @ray 静态对象构造函数在main之前被调用
  • @ray 函数可以在初始化全局变量和静态成员的过程中被调用。
  • 我不知道这些宏在做什么。我会首先在 main 中调用一个 setup 函数,或者如果必须的话使用单例。您可以按所需的顺序进行单例设置。
  • 如果您有一个实例化单个类的静态变量,您可以将所有初始化放入该类并完全控制初始化顺序。您只是无法控制该类相对于其他静态存储的初始化时间。

标签: c++ main


【解决方案1】:

在 main 之前调用的代码块中“隐藏 Init.code”是否是一种好习惯(考虑到现代 c++ 语义)?

由于无法保证全局静态对象的初始化顺序,我一般认为这种做法很糟糕。另一个原因 - 为此类代码提供诊断并非易事,并且会产生人为问题,无需使用此方法即可轻松避免。也有例外,但它们很少见,肯定没有那么多人认为这是一种好的做法。

【讨论】:

  • 我同意。这会产生非常微妙且难以调试的问题。你最好通过按照你希望它们发生的顺序调用函数来明确控制发生的事情。
【解决方案2】:

标准第 3.6.2 节规定,非局部静态变量可以main 的第一条语句之前初始化:

是否动态初始化是实现定义的 具有静态存储持续时间的非局部变量在 main 的第一个语句。

因此,并不是说它们必须main 的第一条语句之前初始化。在 C++ 中没有办法强制在调用 main() 之前初始化任何东西,除了在与 main 相同的编译单元中定义的静态变量。

最好的解决方案是简单地将您的资源管理包含在 main 本身中:

int main()
{
    // Load resources (housekeeping code)

    // Do real work (applicative code)

    // Release resources (housekeeping code)
}

如果您想将应用代码与管家代码分开,常用的方法是使用inversion of control(有时通过template method pattern):

  • 单独的函数或方法专用于应用程序或用户代码
  • main 函数既负责做家务,又负责调用用户代码或应用代码函数或方法。

下面举例说明:

// The function below is expected to exist by the framework
// It must be implemented by the user
int userMain()
{
    // Implement user-code here
}

// The code below is implemented by the framework
// It expects the user to have implemented a function userMain
int main()
{
    FrameWorkData theFrameWorkData;

    // The framework performs its initialization house-keeping here
    theFrameWorkData.initialize();

    // The framework invokes the user-code (inversion of control)
    userMain();

    // The framework performs its clean-up house-keeping here
    theFrameWorkData.cleanup();
}

【讨论】:

  • “辅助主要”是什么意思?像 SDL 一样重新定义 main 对 SDL_main 所做的事情?
  • 是的,除了我的例子倒过来了(我会更正)。 SDL 设计人员显然需要确保用户在使用 SDL 函数之前让 SDL 运行时进行内部管理。因此,真正的应用程序入口点WinMain 由SDL 框架管理并调用用户代码的入口点SDL_main。更多详情请点击此处:stackoverflow.com/a/11976179/5482150
  • 感谢您的帮助:)
【解决方案3】:

在 main 之前调用的代码块中“隐藏 Init.code”是否是一种好习惯(考虑到现代 c++ 语义)?

main 之前运行任何东西的唯一方法是在静态对象的构造函数中进行。

我不能使用静态变量

您已经用完了所有选项。在标准 c++ 中无法实现您所要求的。

回答这样的问题是否是好的做法......这是基于意见的,但我会说,如果库在我明确告诉它初始化之前初始化某些东西,我通常会认为它不好。这将阻止库的用户控制您的库相对于其他库的初始化顺序。当您的库依赖于 SDL 等其他库时,这一点尤其重要。

【讨论】:

    猜你喜欢
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 2016-01-31
    • 1970-01-01
    • 2015-10-01
    相关资源
    最近更新 更多