Как отловить исключение из конструктора без обработки всей функции? - PullRequest
2 голосов
/ 20 октября 2019

Этот вопрос только о том, чтобы найти какое-либо решение, которое не содержит слишком много стандартного кода - хотя это может привести к некоторым решениям, основанным на мнении - я действительно просто ищу любое решение (без слишком большого количества стандартного кода)

Следующее вызывает у меня небольшую головную боль - хотя я легко могу это исправить, я хотел бы избежать слишком большого количества стандартного кода. Следующее недопустимо , но показывает намерение.

char* newBuffer(const char* filename)
{
    auto fm = try { //<--try is not legal here
        boost::interprocess::file_mapping(filename, boost::interprocess::read_only);
    }
    catch (boost::interprocess::interprocess__exception& e) {
        //report error
        return nullptr;//<--this actually makes matters worse since now we cannot just simply wrap in a simpel lambda or function..
    }
    //rest of function ...
}

фрагмент кода Godbolt

Я мог бы просто переместить попытку в началефункция, но это будет означать просто try всю функцию (плохая практика) вместо простого try 'ing file_mapping конструктора. Как бы вы решили эту головоломку и избежали бы попытки блокировать всю функцию? лучше использовать меньший шаблонный код.

Любой ответ также должен касаться проблемы с возвратом nullptr в случае сбоя.

Ответы [ 4 ]

3 голосов
/ 20 октября 2019

Обычно вы объявляете переменную вне блока try:

boost::interprocess::file_mapping fm;
try {
  fm = boost::interprocess::file_mapping(filename, boost::interprocess::read_only);
} catch (boost::interprocess::interprocess__exception& e) {
// Handle error  
  return nullptr;

}

Это требует, чтобы тип был как минимум подвижным.

Вы можете вернуть его из лямбды, но затемвам придется вернуть std::optional или аналогичный, чтобы указать случай ошибки, или выдать другое исключение.

1 голос
/ 20 октября 2019

Это очень похоже на ответ Джеспера Джуля и его комментарий , но я пояснил, как поступить с возвратом nullptr, если конструктор сгенерирует.

char* newBuffer(const char* filename)
{
    auto fm_opt = [&]{
        try {
            return std::make_optional(boost::interprocess::file_mapping(filename, boost::interprocess::read_only));
        }
        catch (boost::interprocess::interprocess__exception& e) {
            //report error
            return std::nullopt;
        }
    }();

    if(!fm_opt.has_value()) return nullptr;

    //rest of function ...
}
1 голос
/ 20 октября 2019

Вы можете использовать лямбду, вызываемую напрямую, например:

auto fm = [&] { try {      
        return boost::interprocess::file_mapping(filename, boost::interprocess::read_only);
    } catch (const boost::interprocess::interprocess__exception& e) {
    //report error
    } }();
// Rest of function
0 голосов
/ 20 октября 2019

Управление временем вызова конструктора - это особенность std::optional (помимо очевидного «представления об отсутствии объекта»):

char* newBuffer(const char *f) {
  std::optional<boost::interprocess::file_mapping> fm0;
  try {
    fm0.emplace(f,boost::interprocess::read_only);
  }
  catch (boost::interprocess::interprocess_exception& e) {
    //report error
    return nullptr;
  }

  auto &fm=*fm0;
  // …
}

Существуют незначительные накладные расходы, связанные с хранением «непустого»состояние optional, но это, вероятно, не имеет значения.

...