Multithreading C++;11 const-我的代码线程安全吗?

Multithreading C++;11 const-我的代码线程安全吗?,multithreading,c++11,thread-safety,constants,Multithreading,C++11,Thread Safety,Constants,我有以下课程: class Object { public: Object() {} const std::string& get_name() const { if(_name.empty()) { std::lock_guard<std::mutex> lock(_lock); // Check if its still empty. Some other thread might have gotten here fir

我有以下课程:

class Object 
{
public:
  Object() {}

  const std::string& get_name() const
  {
    if(_name.empty()) {
      std::lock_guard<std::mutex> lock(_lock);

      // Check if its still empty. Some other thread might have gotten here first
      if(_name.empty()) {
        //Run expensive operation
        _name = get_object_name();
      }
    }

    return _name;
  }

private:
  std::string get_object_name(); // <- Expensive function

  mutable std::mutex  _lock;
  mutable std::string _name;
};
类对象
{
公众:
对象(){}
常量std::string&get_name()常量
{
如果(_name.empty()){
标准:锁和防护锁(锁);
//检查它是否仍然是空的。其他线程可能先到达这里
如果(_name.empty()){
//经营昂贵的业务
_name=get_object_name();
}
}
返回_name;
}
私人:

std::string get_object_name();//否,它不是线程安全的,因为您(读取)在
互斥体
之外访问
\u name
,这会中断同步

一种可能的解决方案是使用标准库提供的
std::call_once
机制

class Object
{
public:
  Object() {}

  const std::string& get_name() const
  {
    std::call_once(flag, [&] { _name = get_object_name(); });

    return _name;
  }

private:
  std::string get_object_name() const; // <- Expensive function

  mutable std::string _name;
  mutable std::once_flag flag;
};
类对象
{
公众:
对象(){}
常量std::string&get_name()常量
{
std::call_once(标志,[&]{_name=get_object_name();});
返回_name;
}
私人:

std::string get_object_name()const;//启动C++11
静态变量以线程安全的方式初始化。
如果获取名称的昂贵操作可以进行
static
我认为以下操作更好:

class Object
{
public:
    const std::string& get_name() const
    {
        static std::string name = expensive_get_name();
        return name;
    }
private:
    static std::string expensive_get_name()
    {
        return "Name";
    }
};

该模式有一个名称:。它在某些环境中有效,而在其他环境中无效。当它不起作用时,原因很微妙。是的,这正是我所担心的。您的
一次呼叫
解决方案非常酷,但我喜欢它。我认为它的开销很小(如果我将其放入循环中,没有任何东西会使我的程序速度降低几个数量级),对吗?@标记
call\u once的可能实现是双重检查锁定模式。开销(初始化后)可能相当于原子加载/获取,它相当于在
X86
std::call_once(flag,[&]{u name=get_object_name();})上的常规加载
似乎更简短、更切题。一个只需调用一次并包含一行代码的方法似乎有点过分。注意:0在实践中,如果您违反此处的要求,简要说明会出现哪些问题可能是好的(特别是,指向字符串的指针可以在指向的内容到达CPU之前到达CPU,而无需同步。)@Yakk我喜欢lambda的建议,更改了itTBH,似乎
get\u object\u name
只有一个函数,所以将其更改为
set\u object\u name
(直接设置
name
)甚至更短。这会导致所有对象具有相同的名称,这与它是一个
const
(即非静态)方法这一事实不符。是的,正如@MSalters所说,这将导致所有对象实例具有相同的名称。第一次调用
get_name()
将初始化该静态变量,它将用于对函数的所有其他调用,甚至用于其他对象。