C++ 为什么(如果是这样的话)标准说用memcpy复制未初始化的内存是UB?

C++ 为什么(如果是这样的话)标准说用memcpy复制未初始化的内存是UB?,c++,language-lawyer,standards,undefined-behavior,trivially-copyable,C++,Language Lawyer,Standards,Undefined Behavior,Trivially Copyable,当一个班级成员在施工时不能有一个合理的含义时, 我不初始化它。显然,这只适用于POD类型,不能不适用 使用构造函数初始化对象 这样做的好处是,除了可以节省CPU周期外,还可以将某些东西初始化到 一个没有意义的值是,我可以检测出这些的错误用法 具有valgrind的变量;如果我只给出这些变量,这是不可能的 一些随机值 比如说, struct MathProblem { bool finished; double answer; MathProblem() : finished(fal

当一个班级成员在施工时不能有一个合理的含义时, 我不初始化它。显然,这只适用于POD类型,不能不适用 使用构造函数初始化对象

这样做的好处是,除了可以节省CPU周期外,还可以将某些东西初始化到 一个没有意义的值是,我可以检测出这些的错误用法 具有valgrind的变量;如果我只给出这些变量,这是不可能的 一些随机值

比如说,

struct MathProblem {
  bool finished;
  double answer;

  MathProblem() : finished(false) { }
};
直到这道数学题解决(完成)才有答案。提前初始化
答案
是没有意义的,因为这可能不是答案<代码>答案
仅在
完成
设置为true后才有意义

因此,在初始化之前使用
answer
是一个错误,完全可以修改

然而,在初始化之前,
answer
的一个普通副本目前也是UB(如果我正确理解了标准),这没有意义:默认的复制和移动构造函数应该只能够创建一个普通副本(又称为memcpy),是否已初始化:我可能希望将此对象移动到容器中:

v.push_back(MathProblem());
然后在容器内处理副本

移动带有未初始化、可复制的成员的对象时,标准是否将其定义为UB?如果是,为什么?这似乎没有道理

移动带有未初始化、可复制的成员的对象时,标准是否将其定义为UB

取决于成员的类型。标准说:

[基本索引]

当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定值,如果未对该对象执行初始化,则该对象将保留不确定值,直到替换该值([expr.ass])

如果评估产生了一个不确定的值,行为是未定义的,以下情况除外:

  • 如果是无符号普通字符类型([basic.basical])或std的不确定值​::​字节类型([cstddef.syn])是通过计算以下内容生成的:

    • 条件表达式的第二个或第三个操作数
    • 逗号表达式的右操作数
    • 转换([conv.integral]、[expr.type.conv]、[expr.static.cast]、[expr.cast])到无符号普通字符类型或标准字符类型的操作数​::​字节类型([cstddef.syn]),或
    • 丢弃的值表达式
    那么操作的结果是一个不确定的值

  • 如果是无符号普通字符类型或std的不确定值​::​字节类型是通过计算简单赋值运算符([expr.ass])的右操作数生成的,该运算符的第一个操作数是无符号普通字符类型或std的左值​::​字节类型,不确定值替换左操作数引用的对象的值

  • 如果初始化无符号普通字符类型的对象时,通过计算初始化表达式生成了无符号普通字符类型的不确定值,则该对象将初始化为不确定值。 如果是无符号普通字符类型或std的不确定值​::​字节类型是在初始化std对象时通过对初始化表达式求值生成的​::​字节类型,则该对象初始化为不确定值

所有例外情况都不适用于示例对象,因此UB适用


memcpy是UB吗

事实并非如此
std::memcpy
将对象解释为字节数组,在这种例外情况下,没有UB。如果您试图读取不确定副本,您仍然有UB(除非上述例外情况适用)


为什么?

< > C++标准不包括大多数规则的基本原理。这一特殊规则自第一个标准以来就存在。它比有关陷阱表示的相关C规则稍微严格一些。据我所知,陷阱处理没有既定的约定,作者不希望通过指定它来限制实现,而是选择将其指定为UB。这还可以让优化人员推断出永远不会读取不确定的值


我可能要将此对象移动到容器中:

v.push_back(MathProblem());

将未初始化的对象移动到容器中通常是一个逻辑错误。目前还不清楚为什么你会想要做这样的事情。

< P> C++标准的设计受到C标准的严重影响,C作者的作者(根据已发布的理论)预期并预期实现将以实施质量为基础。通过有意义地处理程序来扩展语言的语义,即使标准没有“正式”定义这些程序的行为,但这样做显然是有用的。因此,这两个标准都更加重视确保它们在某些情况下不强制执行行为,因为这样做可能会降低某些实现的实用性,而不是确保它们强制执行应该由高质量的通用实现支持的所有行为

在许多情况下,通过保证在任何有效的存储区域上使用
memcpy
,在最坏的情况下,其行为方式与使用一些可能无意义的位模式填充目标一致,并且没有外部副作用,从而扩展语言的语义可能是有用的,如果有的话,很少有人会认为让它做其他事情更容易或更有用。任何人都应该关心
memcpy
的行为是否在特定情况下定义的唯一情况