делать по умолчанию операторы catch throw в C ++ передавать по значению или по ссылке - PullRequest
14 голосов
/ 05 марта 2012

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

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

Ответы [ 3 ]

8 голосов
/ 05 марта 2012

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

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

2 голосов
/ 05 марта 2012

Ты всегда ловишь то, что бросил. Допустим, у вас есть класс исключения

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
     }
 }
1 голос
/ 05 марта 2012

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

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...