Синглтон с объектом, который выбрасывает в ctor - доступ снова? - PullRequest
15 голосов
/ 09 июля 2019

Я могу использовать C ++ 11 или C ++ 14 (или даже C ++ 17). Предположим, у меня есть одноэлементный объект


class MyInstance {
public:
    MyInstance() {
        throw std::runtime_exception("something went wrong"); // Ctor might throw
    }
};

MyInstance& getInstance() {
    static MyInstance obj;
    return obj;
}

Теперь я убедился, что каждый вызов getInstance заключен в

try {
    auto& inst = getInstance();
} catch(std::runtime_error& e) {
   // do something
}

Что меня сейчас интересует, так это: что произойдет, если после сбоя инициализации в конструкторе и выброса и извлечения и информирования пользователя в журналах ... программа снова пропустит в try кодовом пути и снова вызывает getInstance?

Я сделал несколько догадок, но понятия не имею, правы ли они:

Объект имеет статическое хранилище, так что его будет пытаться создать только тогда, когда я думаю? Будет ли возвращение ссылки на неструктурированный объект получит мне висячую ссылку и неопределенное поведение? Будет ли использовать unique_ptr в качестве статической переменной вместо obj, чтобы решить эту проблему, чтобы я мог обращаться к указателю несколько раз, а также проверять, правильно ли построен объект (if (uptr == TRUE))?

Ответы [ 2 ]

9 голосов
/ 09 июля 2019

[stmt.dcl]/4: Динамическая инициализация переменной области блока со статической продолжительностью хранения или продолжительностью хранения потока выполняется при первом прохождении контроля через его объявление;такая переменная считается инициализированной после завершения ее инициализации. Если инициализация завершается с выдачей исключения, инициализация не завершена, поэтому она будет повторена при следующем входе элемента управления в объявление. [..]

Не нужно «угадывать»;Вы могли бы поместить std::cout трассировку внутри MyInstance::MyInstance() и вызвать getInstance() дважды .101

Также не нужны умные указатели;объект либо существует, либо его нет, и внутри getInstance() после объявления невозможно перейти без объявления объекта, потому что вы сгенерировали исключение!

Кстати, это std::runtime_error, а неstd::runtime_exception.

9 голосов
/ 09 июля 2019

Если конструктор выбрасывает объект, не инициализируется .Таким образом, если управление снова пройдет через getInstance, инициализация также будет выполнена снова.

[stmt.dcl] (выделено мое)

4 Динамическая инициализация переменной области блока со статической продолжительностью хранения или продолжительностью хранения потока выполняется при первом прохождении контроля через его объявление;такая переменная считается инициализированной после завершения ее инициализации. Если инициализация завершается выдачей исключения, инициализация не завершена, поэтому она будет повторена при следующем входе элемента управления в объявление .Если управление вводит объявление одновременно во время инициализации переменной, параллельное выполнение должно ожидать завершения инициализации.Если во время инициализации переменной элемент управления повторно вводит объявление, поведение не определено.

...