std :: call_once具有多个昂贵的功能

时间:2018-06-22 08:43:31

标签: c++11 double-checked-locking std-call-once

在昂贵功能数量变化的情况下是否可以使用 std :: call_once

想象一家工厂根据模板参数ResultType计算昂贵的东西,例如三角形网格的边缘邻接或平均顶点法线:

std::unordered_map<std::string, std::unique_ptr<AbstractResult>> mResults;
std::mutex mMutex;

template<typename ResultType, typename ...Params>
const ResultType& getResult(Params&&... params)
{
    std::lock_guard<std::mutex> lock(mMutex);

    const std::string& hash = ResultType::computeHash(std::forward<Params>(params)...);
    auto it = mResults.find(hash);

    if (it == mResults.end())
    {
        // Expensive call
        mResults[hash] = std::make_unique<ResultType>(std::forward<Params>(params)...);

        it = mResults.find(hash);
    }

    return *static_cast<ResultType*>(it->second.get());
}

仅在未创建结果的情况下才需要锁定。为了避免不必要的只读锁定,可以使用双重检查锁定。在C ++ 11中有各种各样的示例如何正确执行此操作,这不是问题。

但是,我的理解是std :: call_once为此提供了一种优雅的解决方案,应避免使用手动双重检查锁定。我知道如何将std :: call_once与单个std :: once_flag变量一起使用。但是,在我的示例中如何使用std :: call_once? 对于每个不同的ResultType,我需要一个std :: once_flag。如何存储一次标志的任意数?我无法将它们存储在用结果的哈希值处理的第二个unordered_map中,因为after_flags既不可复制也不可移动。我在这里想念一些明显的东西吗?

在编译时,已知所有可能的ResultTypes(以及std :: once_flags的数量),数量约为30。但是,没有所有可能的ResultTypes的列表,只有从对getResult<ResultType>的所有调用中才能知道。如果我可以使用模板魔术来解决此问题,我将不胜感激,感谢您的输入。如果有任何特定于MSVC的解决方案,我也很乐意接受。

0 个答案:

没有答案