Эта статья из boost: обработка ошибок и исключений выдвигает следующий программный код:
#include <iostream>
struct my_exc1 : std::exception {
char const* what() const throw();
};
struct my_exc2 : std::exception {
char const* what() const throw();
};
struct your_exc3 : my_exc1, my_exc2 {};
int main() {
try {
throw your_exc3();
} catch(std::exception const& e) {}
catch(...) {
std::cout << "whoops!" << std::endl;
}
}
При компиляции с g ++ (GCC) 5.2.0, я получаю следующее
> g++ -std=c++11 custom_exception.cpp
/tmp/ccmbzPOk.o: In function `my_exc1::my_exc1()':
custom_exception.cpp:(.text._ZN7my_exc1C2Ev[_ZN7my_exc1C5Ev]+0x19): undefined reference to `vtable for my_exc1'
/tmp/ccmbzPOk.o: In function `my_exc1::~my_exc1()':
custom_exception.cpp:(.text._ZN7my_exc1D2Ev[_ZN7my_exc1D5Ev]+0xd): undefined reference to `vtable for my_exc1'
/tmp/ccmbzPOk.o: In function `my_exc2::my_exc2()':
custom_exception.cpp:(.text._ZN7my_exc2C2Ev[_ZN7my_exc2C5Ev]+0x19): undefined reference to `vtable for my_exc2'
/tmp/ccmbzPOk.o: In function `my_exc2::~my_exc2()':
custom_exception.cpp:(.text._ZN7my_exc2D2Ev[_ZN7my_exc2D5Ev]+0xd): undefined reference to `vtable for my_exc2'
/tmp/ccmbzPOk.o:(.rodata._ZTV9your_exc3[_ZTV9your_exc3]+0x20): undefined reference to `my_exc1::what() const'
/tmp/ccmbzPOk.o:(.rodata._ZTV9your_exc3[_ZTV9your_exc3]+0x48): undefined reference to `my_exc2::what() const'
/tmp/ccmbzPOk.o:(.rodata._ZTI9your_exc3[_ZTI9your_exc3]+0x18): undefined reference to `typeinfo for my_exc1'
/tmp/ccmbzPOk.o:(.rodata._ZTI9your_exc3[_ZTI9your_exc3]+0x28): undefined reference to `typeinfo for my_exc2'
collect2: error: ld returned 1 exit status
Я видел аналогичную технику, используемую в другом месте, предлагая мне, что это должно скомпилировать (и связать) без вывода сообщений. (В качестве примера я приведу Энтони Уильямса C ++ Параллелизм в действии п. 45, где он наследует std::exception
делать empty_stack
для примера многопоточного стека.)
Я пытался #include <exception>
и несмотря на то, что это не проблема библиотеки C ++, я даже попробовал -lstdc++
флаг по совету людей с похожими проблемами — от отчаяния.
Я понимаю что в std::exception
, what()
является виртуальным, то есть я должен определить его — поэтому я не уверен, почему он должен компилироваться в первую очередь, но я разочарован тем, что он, очевидно, подходит для других людей.
У меня два вопроса: (1) В чем проблема и почему это работает для других? (2, условно) Новичок в C ++, я должен также спросить, что является хорошим способом реализации what()
(при условии, что мне придется) самым минимальным образом, так как я на самом деле не хочу передавать строку с моим исключением. Мне не нужно наследовать от более глубоких в иерархии, таких как std::runtime_error
,
Согласно C ++ 14 (N3936) [basic.def.odr] / 3:
Виртуальная функция-член используется odr, если она не является чистой.
Так my_exc1::what()
а также my_exc2::what()
являются УСО используемый, хотя они никогда не называются. Тогда у нас есть [basic.def.odr] / 4:
Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе в виде odr; Диагностика не требуется.
Таким образом, вся эта программа имеет неопределенное поведение, но компилятор / компоновщик не обязан ее диагностировать.
Обоснование этого слабого требования состоит в том, чтобы упростить работу компоновщика: если компоновщик может ссылаться без включения вызова этой функции или чего-либо еще, то он может это сделать; Стандарт C ++ не требует, чтобы компоновщик выполнял какой-то анализ программы целиком, чтобы определить, все ли УСО используемый функции имеют тела.
Таким образом, этот код содержит ошибки и должен иметь тела для обеих этих функций. Это также должно иметь #include <exception>
, Для людей, которые скомпилировали и выполнили этот код; их iostream
включены exception
(что разрешено, но не обязательно), и их компоновщик проявил неопределенное поведение как появляющееся для правильной ссылки.
Чтобы обеспечить тело это так же просто, как:
char const *what() const throw() { return ""; }
(при условии, что вы в порядке, делая это в строке). Конечно, вы можете вернуть некоторую другую фиксированную строку, такую как "my_exc1"
, Обратите внимание, что если вы хотите только вернуться ""
тогда вам не нужно повторно объявлять what()
совсем.