Корректный способ инициализировать объект с конструктором броска исключения

Я знаю, что это уродливое и временное решение, но я использую это:

tail -f log / development.log | grep -vE 'актив'

5
задан recipriversexclusion 30 June 2009 в 15:13
поделиться

9 ответов

А как насчет использования указателя (или какой-либо его версии RAII)?

VACaptureSource* input = NULL;

try {
    input = new VACaptureSource(...);
} catch(...) {
    //error handling
}

//And, of course, at the end of the program
delete input;
8
ответ дан 18 December 2019 в 05:36
поделиться

Локальная переменная привязана к блоку, в котором она выделена (например, Java), но она разрушится, как только блок закончится (в отличие от Java), поэтому вы должны либо делать все, что вы хотите в самом блоке try (что может быть нежелательно, если вы хотите обрабатывать только исключения конструктора), или вам следует выделить объект в другом месте (например, в куче) и использовать указатель в родительском блоке для доступа к нему.

4
ответ дан 18 December 2019 в 05:36
поделиться

почему вам нужно ссылаться на него вне блока try ?

Вместо

try {
  VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
}
//catch....

//do stuff with input

вы можете переместить все в блок try:

try {
  VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
  //do stuff with input
}
//catch....

или вы можете выделить это в отдельную функцию, которая вызывается из блока try:

void doStuff(VACaptureSource& input){
  //do stuff with input
}

try {
  VACaptureSource input = VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
  doStuff(input);
}
//catch....

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

11
ответ дан 18 December 2019 в 05:36
поделиться

Могу я просто заметить, что почти любой , но самый тривиальный конструктор может генерировать исключение. Поэтому вы не должны рассматривать исключения как «особые» в каком-то смысле, а вместо этого пишите свой код так, чтобы он работал с ними естественным образом. Это означает использование RAII и других методов, предложенных здесь другими ответами.

3
ответ дан 18 December 2019 в 05:36
поделиться

Вы можете использовать указатель

VACaptureSource* input;
// Create input data object
try {
    input = new VACaptureSource("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");
}
catch( invalid_argument& ia ) {
    cerr << "FD Error: " << ia.what() << endl;
    usage(argv[0]);
}
catch( runtime_error& re ) {
    cerr << "FD Error: " << re.what() << endl;
    usage(argv[0]);
}

И вам нужно освободить объект, когда вы закончите его использовать

delete input
2
ответ дан 18 December 2019 в 05:36
поделиться

Я не могу сказать

VACaptureSource input;

в начале программы, поскольку нет конструктора по умолчанию.

Есть веская причина, по которой вы не создали конструктор по умолчанию: а именно, что VACaptureSource имеет смысл только тогда, когда он связан с файлом. Так что не создавайте конструктор по умолчанию. Вместо этого просто распознайте, что областью действия объекта VACaptureSource является блок try , и используйте его внутри.

2
ответ дан 18 December 2019 в 05:36
поделиться

Как насчет добавления конструктора по умолчанию, который оставляет объект в специальном ненастроенном состоянии? Затем используйте функцию create () для его создания.

Затем вы можете сделать:

VACaptureSource input;
try
{
   input.create("image", "...");
}
catch(...)
{
   ...
}

В зависимости от ситуации это может быть лучше, чем возиться с указателями. Хотя тогда вы также должны проверить, действительно ли был вызван create (), прежде чем что-то делать ...

1
ответ дан 18 December 2019 в 05:36
поделиться

На самом деле я не вижу здесь никаких проблем:

Я бы обновил пару вещей:

  • Перехват исключений по константной ссылке.
  • Компилятор может оптимизировать копию. строительство в вашем коде
    Но без него выглядит аккуратнее. Просто объявите ввод с его параметрами.
  • Я бы реорганизовал конструктор, чтобы он принимал константные ссылочные параметры
    И я бы инициализировал их в списке инициализаторов.
  • Также я бы удостоверился, что элемент 'frame' на самом деле является умным указателем.

Так что я бы сделал это (для ясности).

VACaptureSource::VACaptureSource( std::string const& inputType,
                                  std::string const& inputLocation )
      :type(inputType)
      ,location(inputLocation)
{
    // Other Code that throws.
}
void playWithCode()
{
    // Get input information from user.
    VACaptureSource input("image", "/home/cuneyt/workspace/testmedia/face_images/jhumpa_1.jpg");

    // use the input object.
    // Do not need to play with pointers here.
}
int main()
{
    try
    {
        playWithCode();
    }
    catch( invalid_argument const& ia )
    {    cerr << "FD Error: " << ia.what() << endl;
         usage(argv[0]);
    }
    catch( runtime_error const& re )
    {    cerr << "FD Error: " << re.what() << endl;
         usage(argv[0]);
    }
}
1
ответ дан 18 December 2019 в 05:36
поделиться

Простой. Не создавайте исключений в конструкторе. Вы не только должны заключить конструктор в блок try, но и не сможете очень хорошо обрабатывать память, если поймаете исключение (вызываете ли вы деструктор? Какая часть памяти класса должна быть удалена? )

UPDATE0 : Хотя я не уверен, является ли управление памятью проблемой, если вы используете экземпляр.

UPDATE1 : Хммм, может быть, я думаю об исключениях в деструкторы .

int
main2(int argc, char* argv[])
{
  MyClass class;
  class.doSomething();
}

int
main(int argc, char* argv[])
{
  int result = 0;
    try {
      main2(argc, argv);
    } catch (std::exception& se) {
      // oh noes!
       result = 1;
    }
  return result;
}
0
ответ дан 18 December 2019 в 05:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: