Подтвердить что ты не робот

Делать заявления о выводе catch по умолчанию в С++ pass по значению или ссылке

Как оператор catch по умолчанию catch(...) {} обнаруживает исключение по значению или по ссылке?

Во-вторых, как бросок по умолчанию throw; генерирует исключение по значению или по ссылке?

4b9b3361

Ответ 1

Ловушка catch (...) вообще не дает вам доступ к объекту исключения, поэтому вопрос является спорным. [Исправлено:] Повторное создание с помощью throw; вызывает исходный объект. Если обработчик ухвачен по значению, то изменения в локальной копии не влияют на исходный, восстановленный объект. [/] Подробнее см. 15.3 (особенно пункт 17).

Посмотрите на некоторые из связанных вопросов справа, например этот или этот и этот и этот.

Ответ 2

Вы всегда поймаете то, что бросили. Скажем, у вас есть класс исключений

class MyException {
public:
    int m_data;
    MyException(int data) 
    { 
        printf("MyException::MyException() ctor\n"); 
        m_data = data;   
    }

    MyException(const MyException & other)    { 
        printf("MyException::MyException() copy ctor\n");
    }

    ~MyException()
    {
        printf("MyException::~MyException() dtor\n");
    }
};

1) Если вы указали указатель, вы получите указатель:

Пример 1:

void f()
{
    throw new MyException()
}

void main()
{
    try{
        f();
    }    
    catch(MyException * ex) // You WILL catch the pointer
    {
        delete ex; // You should delete the exception object
    }
    catch(MyException & ex) // You WILL NOT catch the pointer
    {
    }
}

Пример 2:

void main()
{
     try{
         f();
     }
     catch(...) // You WILL catch the pointer, but will be unable to access it
     {
         throw; // You are rethrowing the pointer
     } 
 }

2) Если вы бросили объект, вы поймаете ссылку на него:

Пример 1:

void f()
{
    printf("f BEGIN\n");
    throw MyException(1); // MyException ctor is called
    printf("f END\n");
}

void main()
{
    printf("main BEGIN\n");

    try
    {
        f();
    }
    catch(MyException & ex)  // You WILL catch a reference to created object
    {
       printf("catch MyException: %d\n", ex.m_data);
    } // MyException dtor is called here!!

    printf("main END\n");
}

Производится следующий вывод:

main BEGIN
f BEGIN
MyException::MyException() ctor
catch MyException: 1
MyException::~MyException() dtor
main END

Пример 2:

void main()
{
     try
     {
         f();
     }
     catch(...)  // You WILL catch a reference to created object, 
                 //but will be unable to access it
     {
         throw; // You throw the reference
     }
 }

Ответ 3

Бросок копирует полученное значение в определенное место реализации.
Таким образом, значение копируется при броске (это означает, что тип должен быть скопирован).

Когда вы поймаете, вы можете выбрать улов по значению или ссылке.

catch(X  val) // Catch by value
{
}
catch(Y& val) // Catch by reference
{
}

Идиоматическая причина, по которой нужно уловить, состоит в том, чтобы поймать const-ссылкой. Это связано с тем, что если вы поймаете по значению, существует возможность разрезания, когда исключение копируется из его сохраненного местоположения в значение catch. Если вы поймаете по значению, значение будет уничтожено в конце блока catch. Копия в сохраненном месте уничтожается в конце блока try/catch, где она была схвачена (а не повторно брошена).

Итак, когда вы ловите catch(...), ничего не происходит. Исключением остается в неуказанном местоположении, что исключение уже скопировано.

Когда вы используете throw для повторного выброса исключения. throw;. Опять ничего не происходит, поскольку исключение уже находится в неуказанном месте, и ничего не должно произойти.

Примечание: вызов throw;, когда распространение какого-либо исключения является ошибкой, приведет к вызову std:: terminate.