从 std::exception 继承的 Boost 示例代码不会 link

Boost example code inheriting from std::exception doesn't link

这篇来自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

我在其他地方看到了相同的技术,这向我建议这应该编译(和 link)静默。 (例如,我引用 Anthony Williams C++ Concurrency in Action 第 45 页,他从 std::exception 继承了线程安全堆栈示例 empty_stack。 )

我已经尝试 #include <exception> 尽管这不是 C++ 库问题,但我什至在有类似问题的人的建议下尝试了 -lstdc++ 标志---out绝望。

我知道在 std::exception 中,what() 是虚拟的,这意味着我应该定义它---所以我不确定为什么它应该首先编译,但我对它显然对其他人有用感到沮丧。

我的问题有两个:(1) 问题是什么,为什么对其他人有效? (2,有条件地)C++ 的新手,我还应该问什么是实现 what() 的好方法(假设我必须)以最小的方式,因为我实际上不想传递一个字符串我的例外。我不需要从层次结构的更深层次继承,例如 std::runtime_error.

根据 C++14 (N3936) [basic.def.odr]/3:

A virtual member function is odr-used if it is not pure.

所以 my_exc1::what()my_exc2::what()odr-used,即使它们从未被调用过。然后我们有 [basic.def.odr]/4:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

所以整个程序都有未定义的行为,但不需要 compiler/linker 来诊断它。

这种宽松要求的基本原理是让 link 人的工作更轻松:如果 link 人碰巧能够 link 而无需调用此函数或其他任何内容,那么它就可以这样做; C++ 标准不要求 linker 进行某种整体程序分析以确定是否所有 odr-used 函数都有主体。


所以这段代码有问题,它应该有这两个函数的主体。它还应该有 #include <exception>。对于编译和执行此代码的人;他们的 iostream 包括 exception(这是允许的但不是必需的),他们的 link 人将未定义的行为表现为 link 正确。


要提供正文,很简单:

char const *what() const throw() { return ""; }

(假设您可以在线执行)。当然,您可以 return 一些其他固定字符串,例如 "my_exc1"。请注意,如果您只想 return "" 那么您根本不需要重新声明 what()