Clang Tidy:调用复制构造函数以外的基构造函数

Clang-Tidy: Calling a base constructor other than the copy constructor

本文关键字:构造函数 复制 Tidy 调用 Clang      更新时间:2024-09-29

我从Clang Tidy收到以下消息:

Clang-Tidy: Calling a base constructor other than the copy constructor

代码是这样的:

#include <memory>
#include <set>
using namespace std;
class Node : enable_shared_from_this<Node>
{
public:
explicit Node(Node *parent = nullptr) : parent(parent) { parent->children.insert(shared_from_this()); }
Node(const Node &that) : parent(that.parent), children(that.children) {}

private:
Node *parent; // C++14 "weak pointer"
set<shared_ptr<Node>> children;
};

我在任何地方都找不到Clang Tidy关于这条消息的文档。

它意味着什么,为什么要给予它?

Clang Tidy试图警告您,您的复制构造函数未能调用基类的复制构造函数。GCC在-Wextra:下有类似的警告
<source>: In copy constructor 'Node::Node(const Node&)':
<source>:10:5: warning: base class 'class std::enable_shared_from_this<Node>' should be explicitly initialized in the copy constructor [-Wextra]
10 |     Node(const Node &that) : parent(that.parent) { if (that.parent) that.parent->children.insert(shared_from_this()); }
|     ^~~~

您应该在成员初始值设定项列表中显式使用复制构造函数:

Node(const Node &that) : enable_shared_from_this(that), parent(that.parent) { if (that.parent) that.parent->children.insert(shared_from_this()); }

但是,使用enable_shared_from_this还有其他问题。首先,您必须始终公开继承该类:

class Node : public std::enable_shared_from_this<Node>
// ~~~~~~~~~~^

此外,当拥有的std::shared_ptr尚未构造(尤其是在类构造函数中(时,不允许调用shared_from_this()。在C++17中,这样做将抛出std::bad_weak_ptr,在早期的标准版本中,这是未定义的行为。

在我看来,这个消息相对来说相当清晰,假设它专门指向复制构造函数。不过,它也可以通过提及有问题的基础来改进。

Node继承了enable_shared_from_this<Node>。您手动定义的复制构造函数在初始值设定项列表中没有提到这个基类。因此,基类将默认初始化。在复制构造函数中默认初始化基类或成员很可能不会产生预期效果,更可能是疏忽。这就是clang整洁产生诊断的原因。

在这种特殊情况下,enable_shared_from_this<Node>被默认初始化没有问题,因为它的复制构造函数被定义为执行与其默认构造函数相同的操作。但这是一个罕见的例外。

通过正确初始化基础,您可以满足clang整洁并避免依赖这种特殊情况:

Node(const Node &that) : enable_shared_from_this(that), parent(that.parent) { /*...*/}

但是,这里有更严重的问题。首先,必须公开继承std::enable_shared_from_this。您当前正在私下继承它。

其次,不能在构造函数中使用shared_from_this。当构造函数运行时,正在构造的对象还没有处于std::shared_ptr的控制之下。因此,调用shared_from_this将简单地抛出std::bad_weak_ptr(因为C++17;在此之前未定义的行为(。