【发布时间】:2020-07-18 12:36:08
【问题描述】:
考虑以下类:
template <class Derived>
class BaseCRTP {
private:
friend class LinkedList<Derived>;
Derived *next = nullptr;
public:
static LinkedList<Derived> instances;
BaseCRTP() {
instances.insert(static_cast<Derived *>(this));
}
virtual ~BaseCRTP() {
instances.remove(static_cast<Derived *>(this));
}
};
struct Derived : BaseCRTP<Derived> {
int i;
Derived(int i) : i(i) {}
};
int main() {
Derived d[] = {1, 2, 3, 4};
for (const Derived &el : Derived::instances)
std::cout << el.i << std::endl;
}
我知道在BaseCRTP<Derived> 构造函数(或析构函数)中访问Derived 的成员是未定义的行为,因为Derived 构造函数在BaseCRTP<Derived> 构造函数之后执行 (对于析构函数,反之亦然)。
我的问题是:将this 指针转换为Derived * 以将其存储在链接列表中是未定义的行为,不访问任何Derived 的成员吗? p>
LinkedList::insert 只访问BaseCRTP::next。
使用-fsanitize=undefined 时,我确实收到static_casts 的运行时错误,但我不知道它是否有效:
instances.insert(static_cast<Derived *>(this));
crt-downcast.cpp:14:26: runtime error: downcast of address 0x7ffe03417970 which does not point to an object of type 'Derived'
0x7ffe03417970: note: object is of type 'BaseCRTP<Derived>'
82 7f 00 00 00 2d 93 29 f3 55 00 00 00 00 00 00 00 00 00 00 e8 7a 41 03 fe 7f 00 00 01 00 00 00
^~~~~~~~~~~~~~~~~~~~~~~
vptr for 'BaseCRTP<Derived>'
4
3
2
1
instances.remove(static_cast<Derived *>(this));
crt-downcast.cpp:17:26: runtime error: downcast of address 0x7ffe034179b8 which does not point to an object of type 'Derived'
0x7ffe034179b8: note: object is of type 'BaseCRTP<Derived>'
fe 7f 00 00 00 2d 93 29 f3 55 00 00 a0 79 41 03 fe 7f 00 00 04 00 00 00 f3 55 00 00 08 c0 eb 51
^~~~~~~~~~~~~~~~~~~~~~~
vptr for 'BaseCRTP<Derived>'
此外,这是LinkedList 类的简化版本:
template <class Node>
class LinkedList {
private:
Node *first = nullptr;
public:
void insert(Node *node) {
node->next = this->first;
this->first = node;
}
void remove(Node *node) {
for (Node **it = &first; *it != nullptr; it = &(*it)->next) {
if (*it == node) {
*it = node->next;
break;
}
}
}
}
【问题讨论】:
-
您的
LinkedList是否不能访问Derived的成员(例如:通过使用复制或移动构造函数)? -
@UnholySheep 不,它只是保存一个指针,它不会复制或访问除
BaseCRTP::next之外的任何其他内容。 -
@UnholySheep 我将
LinkedList类添加到我的问题中。 -
根据 CWG1517,
Derived在其基类构造函数完成之前不会在构造中,但是......它如何影响不能static_cast呢? -
能否请您添加您的“真实”链接列表。最后错过了
;,不支持begin()/end()
标签: c++ language-lawyer undefined-behavior crtp downcast