• [翻译]More C++ Idioms 通过初始化挂接(Attach by Initialization)


    (译注:请特别注意“警告一节”。多个编译单元的静态变量初始化顺序问题很有可能给你带来奇怪的行为。在很多情况下通过以下方法可以也可以实现类似该惯用法的效果:

    //框架初始化代码
    //GenerateAppInstance()函数由应用程序员实现
    //返回已初始化好的要挂接类的指针,智能指针,等等,返回后由框架管理。
    //这样可以在明确的点进行初始化并且给应用程序员更多初始化的自由。
    void FrameworkMain()
    {
    ....
    App* app= GenerateAppInstance();
    ....
    }
    //应用程序员初始化代码
    void GenerateAppInstance()
    {
    App* app = new MyApp();
    return app;
    }
    

    目的

    在程序执行开始之前将用户定义对象挂接到框架中

    别称

    带构造器的静态对象(Static-object-with-constructor)

    动机

    某些应用编程框架,例如GUI框架(Microsoft的MFC)和对象请求代理(一些COBRA的实现)使用自己内部的消息循环(也被称为事件循环)来控制整个应用。应用程序员不一定有写应用级别的main函数的自由。通常main函数被埋藏在应用框架的深处(例如MFC中的AfxWinMain)。缺乏访问main函数的权限让程序员无法在主事件循环开始前编写自己的应用特定初始化代码。通过初始化挂接惯用法是一种让应用特定的初始化代码能在框架控制的循环开始之前执行的方法。

    解决方案与示例代码

    在C++中,全局名字空间中的全局对象和静态对象也被称为拥有静态存储存在时间(static storage duration)的对象。(译注:存储存在时间(storage duration)是对象的一个属性(property),定义了包含这个对象的存储的最小潜在生命周期。),他们会在main函数被执行之前初始化。当程序员不被允许写自己的main函数时,拥有静态存储存在时间属性的对象的这个特性可以用来挂接一个对象到一个系统中。例如,可参考下面一个最简单的使用MFC的例子:

    ///// File = Hello.h
    class HelloApp: public CWinApp
    {
    public:
    virtual BOOL InitInstance ();
    };
    ///// File = Hello.cpp
    #include <afxwin.h>
    #include "Hello.h"
    HelloApp myApp; // Global "application" object
    BOOL HelloApp::InitInstance ()
    {
    m_pMainWnd = new CFrameWnd();
    m_pMainWnd->Create(0,"Hello, World!!");
    m_pMainWnd->ShowWindow(SW_SHOW);
    return TRUE;
    }

    上面的例子仅仅只是创建了一个标题为“Hello, World!!  ”的窗口。这里值得注意的关键点在于类型为HelloApp的全局变量myApp. myApp对象在main被执行前被默认的初始化。作为该对象被初始化的副作用,CWinApp的构造函数也会被调用。CWinApp类是框架的一部分,它会调用许多框架中其他类的构造函数。在执行这些构造函数的过程中,全局对象被挂接到框架中(译注:在CWinApp的构造函数中通过ModuleState->m_pCurrentWinApp = thismyApp的指针赋给一个全局变量,以后MFC框架很多地方都会通过AfxGetApp()来取得该指针)。这个对象晚些时候将会被AfxWinMain – MFC中常规main函数的等价物取回。HelloApp::InitInstance成员函数被展现出来是为了代码的完整性,它并不是本惯用法必需的部分。这个函数将在AfxWinMain开始执行后被调用。

    全局和静态对象可以通过多种方法被初始化:默认构造函数,带参数的构造函数,由一个函数的返回值将其赋值,动态初始化等等。

    警告

    在C++中,同一个编译单元中的对象会按照他们被定义的顺序初始化。但是,跨编译单元的拥有静态存储存在时间属性的对象的初始化顺序是不确定的。在名字空间中的对象会在该名字空间中任何一个函数/变量被访问前创建,可能在main函数前或者后。

    对象的销毁顺序将会和创建顺序相反但是创建顺序本身是不确定的。由于这些不确定的行为,当一个静态对象的构造器尝试使用另一个未初始化的静态对象时,静态对象初始化问题将会浮出水面。这个惯用法使你更容易踏入这种陷阱,因为它依赖于一个拥有静态存储存在时间属性的对象。

    已知应用

    MFC

    相关惯用法

    参考资料

    Proposed C++ language extension to improve portability of the Attach by Initialization idiom

    原文链接

    http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Attach_by_Initialization

  • 相关阅读:
    Servlet(九):web.xml文件和server.xml文件
    Servlet(八):ServletContext对象和ServletConfig对象
    Servlet(七):session
    Servlet(六):Cookie
    Servlet(五):请求转发和重定向
    Servlet(四):request和response对象
    Servlet(三):生命周期、常用方法、常见错误
    【php】在Windows2003下的IIS配置php5.4
    Spring AOP监控SQL运行
    算法导论—无向图的遍历(BFS+DFS,MATLAB)
  • 原文地址:https://www.cnblogs.com/shawnhue/p/Attach_by_Initialization.html
Copyright © 2020-2023  润新知