c++ 所有的特殊成员函数都必须是平凡的,才能让类是平凡的可复制的吗?

wrrgggsh  于 2023-10-21  发布在  其他
关注(0)|答案(2)|浏览(152)

在类的子部分中,命名为可简单复制的要求的cppreference page列出了以下要求:

可复制类

一个普通的可复制类是一个

  • 至少有一个合格的复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符,
  • 每个合格的复制构造函数都是平凡的
  • 每个合格的移动构造函数都是平凡的
  • 每个合格的复制赋值运算符都是平凡的
  • 每个合格的移动赋值运算符是平凡的,并且
  • 有一个不可删除的平凡析构函数。

所以,如果有一个平凡的复制操作符,但有一个非平凡的,比如说,移动赋值操作符,那么这个类不是平凡的可复制的吗?我的直觉告诉我,如果你可以通过(简单地)memcpy现有对象(或通过-memcpy赋值给一个构造的对象)来构造一个相同类型的对象,那就是简单的可复制性。

q1qsirdb

q1qsirdb1#

所以,如果有一个平凡的复制操作符,但有一个非平凡的,比如说,移动赋值操作符,那么这个类不是平凡的可复制的吗?
不,根据the C++23 standard,如果复制构造函数和移动赋值运算符符合条件,则不会:

11.2.类class.prop(https://eel.is/c++draft/class.prop)的属性

1.一个 trivially copyable 类是一个类:
1.1.- 具有至少一个合格的复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符(special(https://eel.is/cdraft/special),class.copy.ctor(https://eel.is/cdraft/class.copy.ctor),class.copy.assign(https://eel.is/cdraft/class.copy.assign)),
1.2.- 其中每个合格的复制构造函数、移动构造函数、复制赋值运算符和移动赋值运算符都是平凡的,并且
1.3.- 它有一个平凡的、未删除的析构函数(class.dtor(https://eel.is/c
draft/class.dtor))。
1.一个 trivial class 是一个可以平凡复制的类,它有一个或多个合格的默认构造函数(class.default.ctor(https://eel.is/c++draft/class.default.ctor)),所有这些都是平凡的。
[* 注1*:特别是,一个平凡的可复制类或平凡类没有虚函数或虚基类。- * 结束注解 *]
☆11.4.4.特殊成员函数
1.eligible 特殊成员函数是一个特殊成员函数,它:
6.1.该函数不被删除,
6.2.相关的约束条件(如果有的话)得到满足,并且
6.3.同类的特殊成员函数中,

vybvopom

vybvopom2#

引用是正确的。每个合格的复制/移动操作必须是微不足道的。
普通可复制性应该意味着允许用memcpy替换对象的复制/移动而不影响语义,并且允许以这种方式使用memcpy可能(最初)也只是为了C兼容性。(在C++11拆分POD概念之前,类型实际上必须是C类型才能被memcpy ied。
但是,如果某些特殊的成员函数不是平凡的,那通常不能保证。
例如,如果只有复制赋值而不是移动赋值是平凡的,则

X x{};
Y y;
y = std::move(x);

不应被取代,

X x{};
X y;
std::memcpy(&y, &x, sizeof(X));

因为这跳过了移动分配应该具有的潜在副作用。
因此,X被指定为不可平凡复制。
而且在任何情况下,上面的memcpy都有UB,因为像这样的对象之间的memcpy对象表示的权限也是根据平凡可复制性来指定的。如上所述,我认为这样做的原因是权限的存在(至少最初)纯粹是为了C兼容性。具有非平凡复制/移动操作的类型与C兼容性无关。
即使memcpy对复制对象表示的要求较弱,因此只有一个复制/移动操作需要是平凡的,那么让平凡可复制的概念只需要一个操作是平凡的仍然没有用,因为任何使用它的库函数仍然需要检查单个操作的平凡性,以便将其用于优化。
上面说了所有这些,似乎在标准委员会中对此进行了一些讨论,参见https://github.com/cplusplus/papers/issues/1363

相关问题