【问题标题】:How to lazy init a global var?如何懒惰地初始化一个全局变量?
【发布时间】:2016-12-15 09:46:52
【问题描述】:

我正在制作一个 DLL。我想在命名空间内为每个包含MyTools.h 的编译单元创建一个唯一的全局变量(在我的例子中是一个IBitmap 结构)。这是我在MyTools.h 中的代码:

namespace MyTools
{
    const IBitmap BITMAP_CONTROL_BACKGROUND;
}

它初始化一个“空”变量。我想初始化这个变量,调用 MyClass 的一个方法(返回一个 IBitmap)(稍后将实例化),但是当我在每个将使用这个变量的进程之前执行此操作时:

BITMAP_CONTROL_BACKGROUND = myClass->LoadIBitmap(CONTROL_BACKGROUND, CONTROL_BACKGROUND_PATH, 1);

编译器告诉我BITMAP_CONTROL_BACKGROUND 是常量,所以我不能这样做。

稍后初始化并保持 var 全局的(最佳)方法是什么?

【问题讨论】:

  • 查找单例设计模式及其在 C++ 中的实现。
  • @ilotXXI:单身适用于class。我只需要命名空间/变量,而不是整个类。
  • 删除 const,使用指针(智能指针),在创建时使用 null 进行初始化,这样您就可以检查它是否已经被初始化。根据需要初始化指针...
  • 解决方案:不要使用全局状态;)
  • @SimonKraemer:我无法删除 constIBitmap *BITMAP_CONTROL_BACKGROUND; 会给我链接器错误,因为当我包含多次相同的 .h 时它已经定义

标签: c++ constants global lazy-initialization


【解决方案1】:

首先让我告诉你不要这样做。您正在使用一个全局变量(使用另一个变量来初始化它......)那么它就是 Bad™。是的,您不想在编译单元之间共享该变量,但这会使它变得更加奇怪(IMO)。


如果您仍在阅读并且我没有说服您不要这样做,那么您可以使用函数来初始化 const 表达式。将所有内容放入头文件中:

#pragma once

namespace MyTools {
    namespace Impl {
        IBitmap InitializeControlBackground();
    }

    const IBitmap BITMAP_CONTROL_BACKGROUND(Impl::InitializeControlBackground());
}

IBitmap MyTools::Imp::InitializeControlBackground() {
    return myClass->LoadIBitmap(CONTROL_BACKGROUND, CONTROL_BACKGROUND_PATH, 1);
}

几点说明:

  • InitializeControlBackground() 在嵌套实现 Impl 命名空间中声明,不会污染 MyTools 命名空间。
  • 如果每个编译单元的 InitializeControlBackground() 可能不同,则只需将其移至 .cpp 而不是 .h。

【讨论】:

  • 为什么“不做”?如果我需要初始化跨“未来”对象共享的同一个对象,为什么这会造成痛苦?
  • 第一次点击“全局变量的邪恶” - wiki.c2.com/?GlobalVariablesAreBad 可能值得一读
  • 因为每一个共享对象都会增加依赖和耦合。一个全局变量可能在任何地方都可以访问,然后每个(不受控制的)访问将与所有其他访问耦合(并且它可能会使您的代码面临竞争条件)。
  • 这不是我的例子!在这里,我正在定义“全局”工具,它定义了来自某种“工具”的特定元素,我可以在任何地方使用(并且从不编辑)。我正在研究这个框架,它使用了许多这种方法:github.com/majek/wdl/blob/master/WDL/IPlug/IPlugStructs.h#L30
  • 如你所见,每一个COLOR_元素都是全局的,我可以在需要的时候调用它。在 IBitmap 的情况下,我也想做同样的事情,但我需要在稍后将被初始化的类中使用这样的函数来初始化它们。
【解决方案2】:

这里可以使用一个随便的单例,但是需要提供一个工厂对象来初始化实例。如果您可以随时创建myClass

// Header file.
namespace MyTools
{
    const IBitmap * bitmapControlBackground();
}

// Source file.
const IBitmap * MyTools::bitmapControlBackground()
{
    // Here is a casual singleton. If multi-thread access is possible,
    // here must be a casual way to solve it with mutex.
    static const IBitmap instance = MyClass().LoadBitmap(...);
    return &instance;
}

如果你有一个全局的myClass 变量:

// Source file.
const IBitmap * MyTools::bitmapControlBackground()
{
    // Here is a casual singleton. If multi-thread access is possible,
    // here must be a casual way to solve it with mutex.
    static const IBitmap instance = myClass->LoadBitmap(...);
    return &instance;
}

否则你必须在每次调用时传递它:

// Header file.
namespace MyTools
{
    const IBitmap * bitmapControlBackground(MyClass *creator);
}

// Source file.
const IBitmap * MyTools::bitmapControlBackground(MyClass *creator)
{
    // Here is a casual singleton. If multi-thread access is possible,
    // here must be a casual way to solve it with mutex.
    static const IBitmap instance = creator->LoadBitmap(...);
    return &instance;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2019-01-24
    相关资源
    最近更新 更多