为什么没有用户提供的cp/mv ctor并且具有虚函数但没有虚拟基的类没有"trival cp/mv ctor"?

Why do classes with no user-provide cp/mv ctor and have virtual functions but no virtual bases not have "trival cp/mv ctor"?

本文关键字:mv ctor cp 虚拟 trival 函数 用户 为什么      更新时间:2023-10-16

根据标准:

类 X 的复制/移动构造函数如果不是用户提供的,并且

如果— 类 X 没有虚函数 (10.3) 和 没有虚拟基类 (10.1),以及

— 选择复制/移动每个直接基类子对象的构造函数是微不足道的,并且

— 对于类类型(或其数组)的每个 X 非静态数据成员,构造函数 选择复制/移动该成员是微不足道的;

否则,复制/移动构造函数是不平凡的。

我认为该标准引入了"trival cp/mv ctor"的概念来推断你可以使用 std::memcpy 复制类而不是调用构造函数,并且不会有未定义的行为。

但是,该标准不允许虚函数的存在,我认为这违背了"trival cp/mv ctor"的精神。带有指向虚函数的 vtable 的类仍然可以使用 std::memcpy 复制并具有正确的行为。毕竟,你不能在运行时更改类的 vtable——这会破坏这个类的其他实例。

那么,为什么没有用户提供的cp/mv ctor,有虚函数但没有虚拟基的类不能有"trival cp/mv ctor"呢?

这不是一个简单的类型,因为确保"vptr"指向正确的"vtable"并不像复制指针的值那么简单。我们可以复制出基本的子对象。我们不需要总是处理派生最多的对象类型。

void bar(base const& b) { 
b.overriden_function();
}
void foo(base const& b) {
auto other_b = b;
bar(other_b);
}
int main() {
derived d;
foo(d);
}

让我们假设base微不足道的。所以复制是按照你说的完成的。b的 vptr 指向derived的 vtable 。所以现在我们得到了一个对象,其 vtpr 指向错误的 vtable。我们调用一个覆盖函数。

繁荣!

考虑一个简单的例子:

#include <iostream>
struct ConcreteBase {
virtual void method() {
std::cout << "Basic implementation" << std::endl;
}
};
struct Derived: ConcreteBase {
Derived(int x): extraState{x} {}
void method() {
std::cout << "Overridden (" << extraState << ')' << std::endl;
}
private:
const int extraState;
};
int main() {
ConcreteBase const &b = Derived(42);
ConcreteBase b1{b};
b1.method();
}

你到底如何使用memcpy来复制这里的vtable?(更广泛地说,你会如何轻视ConcreteBase的复制ctor?)

相关文章: