boost: Error and Exception Handling的这篇文章提出了以下程序代码:
#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
我已经看到了其他地方使用的相同技术,向我建议这应该静默编译(和链接)。 (作为一个例子,我引用了Anthony Williams C ++ Concurrency in Action p.45,他继承自std::exception
以使empty_stack
为线程安全堆栈示例。)
我试过#include <exception>
尽管事实上这不是一个C ++库问题,我甚至在有类似问题的人的建议下尝试了-lstdc++
标志 - 出于绝望
我明白在std::exception
中,what()
是虚拟的,这意味着我应该定义它 - 所以我不确定为什么它应该首先编译,但我很沮丧它显然对其他人有用。
我的问题是两个:(1)问题是什么,为什么它适用于其他人? (2,有条件的)C ++的新手,我也应该问一下以最小的方式实现what()
(假设我必须)的好方法,因为我实际上并不想传递一个字符串我的例外。我不需要继承层次结构中的更深层次,例如std::runtime_error
。
答案 0 :(得分:1)
根据C ++ 14(N3936)[basic.def.odr] / 3:
如果虚拟成员函数不纯,则使用该函数。
所以my_exc1::what()
和my_exc2::what()
odr-used ,即使它们从未被调用过。然后我们有[basic.def.odr] / 4:
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。
因此整个程序具有未定义的行为,但不需要编译器/链接器来诊断它。
这个松散要求的基本原理是使链接器的工作更容易:如果链接器恰好能够链接而不包括对此函数的调用或其他任何东西,那么它可以这样做; C ++标准不要求链接器进行某种程序的整个程序分析,以确定所有 odr-used 函数是否都有正文。
所以这段代码被窃听,它应该有这两个函数的主体。它也应该有#include <exception>
。对于编译和执行此代码的人;他们的iostream
包括exception
(允许但不是必需的),并且他们的链接器将未定义的行为表现为正确链接。
提供一个正文,它就像:
char const *what() const throw() { return ""; }
(假设你做得好内联)。当然,您可以返回其他一些固定字符串,例如"my_exc1"
。请注意,如果您只想返回""
,则根本不需要重新声明what()
。