【问题标题】:coinitialize() and static confusioncoinitialize() 和静态混淆
【发布时间】:2012-03-01 05:20:50
【问题描述】:

我有一个静态 const 类成员的情况,它调用一个静态函数来初始化它的值:

//A.h
class A
{
public:
static const int NUM;
static int Function();
};

//A.cpp
const int A::NUM = A::Function();

问题是 A::Function() 有一个局部静态变量,需要通过调用 CoInitialize() 来初始化 COM 库:

//A.cpp
int A::Function()
{
static vartype m;
if(SUCCEEDED(CoInitialize(NULL)))
//Now m can be used and initialized.
// m.CreateInstance....
} 

我之前在 WinMain 中调用了 CoInitialize():

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
if(SUCCEEDED(CoInitialize(NULL)))
    {
    MyApp* app = new MyApp;

    app->Run();

    delete app;

    CoUninitialize();
    }

return 0;
}

但是由于在调用 A::Function() 时初始化静态成员变量 A::NUM 时调用了 ConInitialize(),并且这将在 WinMain 中的代码执行之前发生,我想我可以将其从我的 WinMain:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
//if(SUCCEEDED(CoInitialize(NULL)))
    {
    MyApp* app = new MyApp;

    app->Run();

    CoUninitialize();
    }

return 0;
}

现在程序运行良好,但当我退出时它因访问冲突而崩溃。谁能解释一下为什么会这样?

编辑:我在想,由于静态变量应该在程序期间持续存在,所以当我调用 CoUninitialize() 时,本地静态变量 m(需要 COM 库)会遇到问题。崩溃似乎与这个局部变量m有关。但问题是,我什么时候可以为需要 COM 库的静态变量调用 CoUninitialize()?如果我取消注释 WinMain 中的 if 语句,问题似乎就消失了,但我认为那是因为我最终调用了 CoInitialize() 两次,而 CoUninitialize() 只调用了一次。

【问题讨论】:

    标签: c++ com static


    【解决方案1】:

    首先,您可以在这种情况下使用 RAII。只需定义一个简单的类,如下所示:

    class com_scope
    {
        com_scope(com_scope const&);
        com_scope& operator= (com_scope const&);
    public:
        com_scope() 
        {
            ::CoInitialize(NULL);
        }
        com_scope(DWORD dwCo)
        {
            ::CoInitializeEx(NULL, dwCo);
        }
        virtual ~com_scope() throw()
        {
            ::CoUninitialize();
        }
    }
    

    然后定义一个静态的 const com_scope _AppComScope。声明前

    const int A::NUM = ...
    

    此代码将在第一次调用 A::Function 之前初始化 COM 环境,并在执行结束时清理。

    您的问题极有可能是在最终使用一些 com 引用之前破坏了 COM 环境。这解释了当您从 WinMain 中删除 ::CoUnitialize 后问题就会消失的事实。

    附言

    虽然这是一个坏主意,但你不能在你的主线程中调用 ::CoUninitialize 因为操作系统会在你的程序完成时进行清理

    附言

    另外,我必须承认应该在 CPP 文件中定义 _AppComScope,在该文件中为 A::NUM 赋值。否则,标准不保证初始化的顺序

    【讨论】:

    • 如果我创建一个这种类类型的静态变量(在其构造函数中初始化COM库),并在同一个复杂单元中的其他静态成员之前定义它,这意味着COM库将为所有跟随它的静态成员做好准备,对吗?而当静态变量在程序终止时被销毁时,它们是否总是以相反的顺序被销毁,这样 com_object 才会最后被销毁?如果是这样,这似乎可行,但如果我在其他调用 A::Function() 的复杂单元中有其他静态成员,我会不会走运?
    • 你是对的。对象将以相反的顺序被销毁。如果您将这些声明放在单独的单元中,标准没有定义初始化\销毁的顺序。
    • @user987280, 在使用 COM 时,明确控制每个 com 引用的生命周期非常重要。因此,我建议您重构代码以避免过度使用静态变量。
    猜你喜欢
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多