0

我有一个适用于某些数值的 C++ 库,这些值在编译时不可用,但在运行时立即可用,并且基于与机器相关的详细信息,简而言之,我需要显示分辨率、CPU 核心数和很快。

我的问题的关键点是:

  • 我不能要求用户输入这个值(我的 lib 的编码器/用户和最终用户)
  • 我只需要在应用程序启动后进行预热,这是一次只有一次的事情
  • 此值稍后由方法和类使用

可能的解决方案是:

  • 构建一个数据结构Data,声明一些用于Data dummy存储dummy所有内容的变量的名称,并且构造函数将处理相关值的一次性初始化
  • 将第一个解决方案之类的东西包装在一个方法中,WarmUp()然后将此方法放在开始之后main()(这也是一个简单的记住和使用的东西)

仍未解决的大问题是:

  • 用户可以声明多个数据结构,因为Data它是一种类型,并且在 C++ 中抛出 2-4-5-17 个相同类型的变量没有限制
  • WarmUp()方法可能对其他类的设计有一点干扰,也可能发生该WarmUp()方法用于本地方法而不是main().

当我无法控制库的实际使用时,我基本上需要在运行时强制创建 1 个特定类型的 1 个单个实例,或者至少我需要以一种用户会立即理解的方式来设计它错误是继续保持图书馆的使用尽可能直观和简单。

你能看到解决方案吗?


编辑:

由于我也在尝试获得多线程兼容的数据结构,因此我的问题也更加困难。

4

3 回答 3

2

如何使用懒惰创建单例?例如

struct Data
{
  static Data & instance()
  {
    static Data data_;
    return data_;
  }
private:
  Data()
  {
    //init
  }
}

Data将在首次使用时初始化,当您调用时Data::instance()

编辑:至于多线程,请阅读C++ 中的高效线程安全单例

Edit2 使用 boost::call_once实现

于 2013-04-05T07:48:05.103 回答
0

预热通常与性能问题有关(让我想到处理器缓存,请参阅 GCC 的__builtin_prefetch)。

也许你想做一个单例类,有很多解决方案(例如这个 C++ 单例教程)。

此外,如果性能是主要问题,您可以考虑在初始化(甚至在安装)时给出配置的参数。然后,您可以专门化您的代码,也许就像拥有模板并首先通过发出(在运行时 = 初始化时)适当的 C++ 存根源代码并编译它(在“运行时”,例如在初始化时)并动态加载它(使用插件和dlopen...)。另请参阅此答案

于 2013-04-05T07:49:34.160 回答
0

首先,正如其他人所说,对此的明显(也是最好的)答案是单例。但是,由于您添加了多线程要求:有两种解决方案,具体取决于对象是否将通过使用单例的代码进行修改。(根据您的描述,我认为没有。)如果不是,那么使用单例的“幼稚”实现就足够了,并确保在启动线程之前初始化单例。如果在您进入 main 之前没有启动线程(否则我认为这是不好的做法),那么类似以下的内容在很大程度上就足够了:

class Singleton
{
    static Singleton const* ourInstance;
    Singleton();

    Singleton( Singleton const& );
    Singleton& operator=( Singleton const& );

public:
    static Singleton const& instance();
};

并在实施中:

Singleton const* Singleton::ourInstance = &Singleton::instance();

Singleton const&
Singleton::instance()
{
    if ( ourInstance == NULL ) {
        ourInstance = new Singleton;
    }
    return *ourInstance;
}

不需要锁定,因为一旦线程启动,没有线程将修改任何内容。

如果单例是可变的,那么您必须保护对它的所有访问。你可以做类似上面的事情( const显然没有 ),并将锁定留给客户端,但在这种情况下,我更喜欢锁定instance函数,并返回一个std::shared_ptr带有释放锁的删除器,这是获取的在instance函数中。我认为像下面这样的东西可以工作(但我从来没有真正需要它,所以没有尝试过):

class Singleton
{
    static Singleton* ourInstance;
    static std::mutex ourMutex;

    class LockForPointer
    {
    public:
        operator()( Singleton* )
        {
            Singleton::ourMutex.unlock();
        }
    };
    class LockForInstance
    {
        bool myOwnershipIsTransfered;
    public:
        LockForInstance
            : myOwnershipIsTransfered( false )
        {
            Singleton::ourMutex.lock();
        }
        ~LockForInstance()
        {
            if ( !myOwnershipIsTransfered ) {
                Singleton::ourMutex.unlock();
            }
        }
        LockForPointer transferOwnership()
        {
            myOwnershipIsTransfered = true;
            return LockForPointer();
        }
    };
public:
    static std::shared_ptr<Singleton> instance();
};

和实施:

static Singleton* ourInstance = NULL;
static std::mutex ourMutex;

std::shared_ptr<Singleton>
Singleton::instance()
{
    LockForInstance lock;
    if ( ourInstance == NULL ) {
        ourInstance = new Singleton;
    }
    return std::shared_ptr<Singleton>( ourInstance, lock.transferOwnership() );
}

这样,相同的锁用于检查 null 和访问数据。

于 2013-04-05T10:34:04.833 回答