Catching std:: exception по ссылке?

У меня есть глупый вопрос. Я прочитал эту статью о std:: exception http://www.cplusplus.com/doc/tutorial/exceptions/

В catch (exception& e) он говорит:

Мы поместили обработчик, который ловит объекты исключений по ссылке (обратите внимание на амперсанд и после типа), поэтому он также ловит классы, производные от исключения, например наш myex-объект класса myexception.

Означает ли это, что, используя "&" вы также можете перехватить исключение родительского класса? Я думал и предопределен в std:: exception, потому что лучше передать e (std:: exception) в качестве ссылки, чем объект.

Ответы

Ответ 1

Причиной использования & с исключениями является не столько полиморфизм, сколько исключение slicing. Если бы вы не использовали &, С++ попытался бы скопировать брошенное исключение во вновь созданный std::exception, потенциально потеряв информацию в этом процессе. Пример:

#include <stdexcept>
#include <iostream>

class my_exception : public std::exception {
  virtual const char *what() const throw() {
    return "Hello, world!";
  }
};

int main() {
  try {
    throw my_exception();
  } catch (std::exception e) {
    std::cout << e.what() << std::endl;
  }
  return 0;
}

Это будет печатать сообщение по умолчанию для std::exception (в моем случае, St9exception), а не Hello, world!, потому что исходный объект исключения был потерян путем нарезки. Если мы изменим это на &:

#include <stdexcept>
#include <iostream>

class my_exception : public std::exception {
  virtual const char *what() const throw() {
    return "Hello, world!";
  }
};

int main() {
  try {
    throw my_exception();
  } catch (std::exception &e) {
    std::cout << e.what() << std::endl;
  }
  return 0;
}

Теперь мы видим Hello, world!.

Ответ 2

Означает ли это, что, используя "&" вы также можете поймать исключение родительского класса?

Нет, это не увеличивает объем использования исключений (например, из родительского класса класса, содержащего код try/catch).

Он также не увеличивает типы исключений, которые могут быть пойманы, по сравнению с ловом по значению (catch(std::exception e) без &), вы все равно поймаете каждое исключение, которое либо равно std::exception, либо происходит от него).

То, что он увеличивает, - это количество данных, которое вы действительно получите, когда поймаете исключение.

Если возникает исключение, которое происходит от std::exception, и вы его поймаете по значению, то вы выбрасываете какое-либо дополнительное поведение в этом классе исключений. Он разбивает polymorphism на класс исключения, из-за Slicing.

Пример:

class MyException : public std::exception
{
public:
    virtual const char* what() const
    {
        return "hello, from my exception!";
    }
};

// ...

try
{
    throw MyException();
}
catch(std::exception& e)
{
    // This will print "hello, from my exception!"
    std::cout << e.what() << "\n";
}

// ...

try
{
    throw MyException();
}
catch(std::exception e)
{
    // This will print "Unknown exception"
    std::cout << e.what() << "\n";
}

Ответ 3

Нет & не имеет никакого отношения к полиморфному характеру обработчиков исключений. Их формулировка очень плохая, она, похоже, указывает, что & как-то ответственна. Это не тот случай. Вы правы, & просто передает по ссылке, которая немного эффективнее.

Также, как правило, вы действительно должны стараться избегать cplusplus.com.

Обновленная ссылка: Что не так с cplusplus.com

Ответ 4

Использование ссылки на исключение здесь может уменьшить создаваемые временные объекты, а также сохранить полиморфизм.