具有多重继承和抽象基础的自定义异常中的用户定义的空构造函数 class

User-defined empty constructors in custom exception with multiple inheritance and abstract base class

我设计了几个自定义异常,它们都继承自相同的抽象基础 class custom::exception 和相应的标准 exception 由于多重继承。 因此在我的自定义异常中有一个特定的层次结构,我可以一般地或特定地捕获它们。

现在我打开所有警告,GCC 没有任何问题,但 clang 抱怨虚拟析构函数:

#include <iostream>
#include <stdexcept>

namespace custom {
    struct exception;
    struct buffer_overflow;
    struct null_pointer;
    struct out_of_range;
    //...
}

struct custom::exception {
    virtual ~exception() noexcept {}
    virtual const char* what() const noexcept = 0;
};

struct custom::null_pointer : public custom::exception, public std::logic_error {
    null_pointer(const std::string &str): std::logic_error(str) {}
    const char* what() const noexcept override { return std::logic_error::what(); }
};

int main(){
    try{
        throw custom::null_pointer("[ERROR] NULL pointer exception !");
    }
    catch(const custom::exception &error){
        std::cout << error.what() << std::endl;
    }
}

使用 g++ 输出 (MinGW.org GCC-8.2.0-3) :

[ERROR] NULL pointer exception !

用 clang++ 输出 version 6.0.0-1ubuntu2 :

test.cpp:13:13: warning: definition of implicit copy constructor for 'exception' is deprecated because it has a
      user-declared destructor [-Wdeprecated]
    virtual ~exception() noexcept {}
            ^
test.cpp:17:16: note: in implicit copy constructor for 'custom::exception' first required here
struct custom::null_pointer : public custom::exception, public std::logic_error {
               ^
test.cpp:24:15: note: in implicit move constructor for 'custom::null_pointer' first required here
        throw custom::null_pointer("[ERROR] NULL pointer exception !");
              ^
1 warning generated.
[ERROR] NULL pointer exception !

我不是很明白,因为custom::exception是抽象的,不包含任何成员变量,所以不需要用户自定义构造函数。但是如果我定义那些,clang 不会抱怨:

struct custom::exception {
    exception() noexcept {}
    exception(const exception&) noexcept {}
    virtual ~exception() noexcept {}
    virtual const char* what() const noexcept = 0;
};

我的问题是:

  1. 哪个编译器是正确的?
  2. 为什么我必须像上面那样定义空的默认构造函数和复制构造函数?

谢谢。

相关问题:

您遇到了 Warning: definition of implicit copy constructor is deprecated 遇到的相同问题:

在 C++ 标准 D.2 Implicit declaration of copy functions [depr.impldec] 中,C++17 N4659 草案指出:

The implicit definition of a copy constructor as defaulted is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. The implicit definition of a copy assignment operator as defaulted is deprecated if the class has a user-declared copy constructor or a user-declared destructor (15.4, 15.8). In a future revision of this International Standard, these implicit definitions could become deleted (11.4).

这给出了

的答案

1.: 两个编译器都是正确的,clang 实际上会警告你弃用,gcc 不会,这也没关系。

这没问题,因为 D(0) 对其发出警告是可选的,甚至 [[deprecated]] 属性也不是强制发出警告的:

An implementation may declare library names and entities described in this section with the deprecated attribute

2。逼你想想所谓的Rule of Three: 三个规则指出,由于您需要定义一个构造函数,因此您可能需要一个复杂的复制和/或移动构造函数。通过强制你显式定义它们,即使使用 default,它起到了保险的作用,class 作者已经考虑了切片和其他问题。然而,由于隐式或默认的复制构造函数只是复制你的基础和元素,你应该没问题。

你可以default,这基本上和隐含定义的东西一样,但你想要一个虚拟析构函数,否则是一样的:

exception() noexcept = default;
exception(const exception&) noexcept = default;
virtual ~exception() noexcept = default;