Статический указатель на потокобезопасность инициализации объекта
В C++11 следующее является поточно-ориентированным:
void someFunc()
{
static MyObject object;
}
Но что насчет
void someFunc()
{
static MyObject *ptr = new MyObject();
}
Это тогда потокобезопасный или нет?
Как было отмечено в комментариях @Nawaz, возможно, что конструктор MyObject не является поточно-ориентированным, поэтому давайте разделим вопрос на части:
1) Если ctor является поточно-ориентированным (он не имеет доступа к общему состоянию), это static MyObject *ptr = new MyObject();
потокобезопасный? Другими словами, это static int *ptr = new int(0);
потокобезопасный?
2) Если ctor не является потокобезопасным, но объект создается только путем вызова someFunc
из разных потоков, и конструктор никогда не используется нигде, будет ли это потокобезопасным?
1 ответ
Да, это потокобезопасный. Это следует из той же гарантии, которая применима к первому примеру, что одновременное выполнение функции будет инициализировать статическую переменную ровно один раз. Поскольку статический указатель должен быть инициализирован ровно один раз, а способ его инициализации определяется как вызов new
, затем new
и конструктор, который он вызывает, будет вызываться ровно один раз. Предполагая, что конструктор new
объект не делает ничего опасного, все это будет в безопасности.
Спасибо Мэтью М. за то, что он указал на одно исключение: если инициализация сработает, она будет предпринята снова при следующем (отложенном или будущем) вызове функции. Это все еще потокобезопасный, хотя, потому что вторая попытка не начнется, пока после того, как первая не удалась.
Тем не менее, такой код вызывает беспокойство, потому что, похоже, он может привести к утечке памяти, которая может быть помечена автоматическими инструментами, такими как valgrind, поэтому было бы лучше как-то этого избежать. Даже класс со статическим членом мог бы быть лучше, так как тогда было бы легче очистить статический специальный метод, который вызывается до завершения программы.