为什么没有用户提供的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"?
根据标准:
类 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?)
- std::is_base_of表示ctor编译错误
- 对复制 CTOR 和 CTOR 的未定义引用
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- C++成功复制动态分配的 obj 而不复制 ctor?
- 如何测试采用 std::initializer_list 的 ctor 具有编译时已知长度?
- 为什么 std::optional::value_or 没有默认 ctor 类型的专用化?
- 在CTOR vs Connect方法中提升套接字与stream_socket端点
- 给定一个右值,为什么移动ctor比常量复制ctor更匹配
- std::任何只用于移动的模板,其中副本ctor内的static_assert等于编译错误,但为什么
- C2436 '{ctor}':构造函数初始值设定项列表中的成员函数或嵌套类
- 为什么在 ctor 的参数列表中将成员"x"的类型替换为"decltype(x)"会破坏类模板参数推导?
- 模板 ctor 类型推导不起作用(没有匹配的构造函数用于初始化 ...)与函数<>参数
- 为什么"non-standard syntax; use '&' to create a pointer to member"在 CTOR 中使用线程?
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 调用了Copy ctor而不是move ctor
- 委派的 ctor 是否受参数计算顺序的影响?
- 由于 C++17 支持数组shared_ptr,这是否意味着在 ctor 和重置中不再需要 T[] 的显式删除器?
- 为什么部分初始化一个类然后调用委托 ctor 失败?
- 返回函数中带有 2 个可选 ctor 的对象
- 为什么没有用户提供的cp/mv ctor并且具有虚函数但没有虚拟基的类没有"trival cp/mv ctor"?