静态指针指向对象初始化线程安全

Vla*_*mir 9 c++ thread-safety static-initialization c++11

在C++ 11中,以下是线程安全的:

void someFunc()
{
    static MyObject object;
}
Run Code Online (Sandbox Code Playgroud)

但是关于

void someFunc()
{
    static MyObject *ptr = new MyObject();
}
Run Code Online (Sandbox Code Playgroud)

这是否是线程安全的?

正如@Nawaz在评论中提到的那样,可能MyObject构造函数不是线程安全的,所以让我们将问题分成几部分:

1)如果ctor是线程安全的(它不访问任何共享状态),这是否是static MyObject *ptr = new MyObject();线程安全的?换句话说,是static int *ptr = new int(0);线程安全的吗?

2)如果ctor不是线程安全的,但是只能通过someFunc从不同的线程调用来创建对象,并且构造函数从未在其他任何地方使用过,那么这是否是线程安全的呢?

Joh*_*nck 9

是的,它是线程安全的.这遵循适用于第一个示例的相同保证,即函数的并发执行将初始化静态变量一次.由于静态指针必须初始化一次,并且初始化它的方式被定义为对它的调用new,然后new它调用的构造函数将被调用一次.假设new对象的构造函数没有做任何不安全的事情,那么整个事情就是安全的.

感谢Matthieu M.指出了一个例外:如果初始化抛出,将在下一次(挂起或将来)调用该函数时再次尝试.它仍然是线程安全的,因为第二次尝试直到第一次尝试失败后才会开始.

话虽如此,看到这样的代码是令人担忧的,因为它似乎可能导致内存泄漏,可能会被像valgrind这样的自动化工具标记出来,所以最好以某种方式避免这种情况.即使是具有静态成员的类也可能更好,因为在程序结束之前使用特殊方法清理静态会更容易.

  • 注意:实际上,*恰好一次*是错误的.它是*一次一个*,但表达式可能会被多次评估(连续)直到成功=>如果在初始化期间出现异常,则知道该对象不会被初始化并且下次控制流时会再次尝试初始化通过定义. (3认同)