C++ 正在复制具有未初始化成员的结构
复制某些成员未初始化的结构是否有效 我怀疑这是一种未定义的行为,但如果是这样的话,将任何未初始化的成员留在结构中(即使这些成员从未直接使用过)会非常危险。所以我想知道标准中是否有允许它的东西 例如,这是否有效C++ 正在复制具有未初始化成员的结构,c++,initialization,copy-constructor,undefined-behavior,C++,Initialization,Copy Constructor,Undefined Behavior,复制某些成员未初始化的结构是否有效 我怀疑这是一种未定义的行为,但如果是这样的话,将任何未初始化的成员留在结构中(即使这些成员从未直接使用过)会非常危险。所以我想知道标准中是否有允许它的东西 例如,这是否有效 struct数据{ INTA,b; }; int main(){ 数据; 数据a=5; 数据2=数据; } 通常,复制未初始化的数据是未定义的行为,因为该数据可能处于捕获状态。报价页: 如果对象表示不表示对象类型的任何值,则称为陷阱表示。除了通过字符类型的左值表达式读取陷阱表示之外,以任何
struct数据{
INTA,b;
};
int main(){
数据;
数据a=5;
数据2=数据;
}
通常,复制未初始化的数据是未定义的行为,因为该数据可能处于捕获状态。报价页:
如果对象表示不表示对象类型的任何值,则称为陷阱表示。除了通过字符类型的左值表达式读取陷阱表示之外,以任何方式访问陷阱表示都是未定义的行为
对于浮点类型和某些平台上的整数陷阱表示,可以使用信令NAN
但是,对于类型,可以使用
memcpy
复制对象的原始表示。这样做是安全的,因为不解释对象的值,而是复制对象表示的原始字节序列。是,如果未初始化的成员不是无符号窄字符类型或std::byte
,然后,使用隐式定义的复制构造函数复制包含此不确定值的结构在技术上是未定义的行为,因为它用于复制具有相同类型的不确定值的变量
这适用于此处,因为隐式生成的复制构造函数(union除外)定义为通过直接初始化单独复制每个成员,请参阅
这也是本次活动的主题
不过,我想在实践中你不会有任何问题
如果希望100%确定,如果类型为,则使用std::memcpy
始终具有定义良好的行为,即使成员具有不确定的值
撇开这些问题不谈,假设不要求类具有指定的值,那么无论如何,在构造时都应该使用指定的值正确初始化类成员。您可以使用默认成员初始值设定项语法轻松地执行此操作,例如,值初始化成员:
struct Data {
int a{}, b{};
};
int main() {
Data data;
data.a = 5;
Data data2 = data;
}
在某些情况下,如所描述的,C++标准允许编译器以任何他们的客户最有用的方式处理构造,而不要求这种行为是可预测的。换句话说,这样的构造调用“未定义的行为”。然而,这并不意味着,这些结构意味着“禁止”,因为C++标准明确地放弃了对“合格”的程序“允许”的管辖权。虽然我不知道C++标准的任何公开的理论文档,但是它描述了像C89这样的未定义行为,这将意味着预期的含义是相似的:“未定义的行为使实施者可以不捕获某些难以诊断的程序错误。它还确定了可能的一致性语言扩展领域:实现者可以通过提供官方未定义行为的定义来扩充语言”
在许多情况下,最有效的处理方法是编写下游代码将关心的结构部分,而忽略下游代码不关心的部分。要求程序初始化结构的所有成员,包括那些永远不会关心的成员关心,会不必要地妨碍效率 此外,在某些情况下,让未初始化的数据以非确定性方式运行可能是最有效的。例如:struct q { unsigned char dat[256]; } x,y;
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
temp.dat[arr[i]] = i;
x=temp;
y=temp;
}
如果要求程序员在复制之前显式地编写temp.dat
的每个元素,包括下游不关心的元素,那么效率的提高是不可能的
另一方面,在某些应用程序中,避免数据泄漏的可能性非常重要。在此类应用程序中,可能需要一个版本的代码,该版本的代码被检测以捕获任何复制未初始化存储的尝试,而不考虑下游代码是否会查看它,或者可能需要e实施保证任何内容可能泄漏的存储将被归零或以其他方式被非机密数据覆盖
从我可以看出,C++标准没有试图说任何这些行为都比其他行为更有用,以证明它的授权。讽刺的是,这种缺乏规范可能是为了促进优化,但是如果程序员不能利用任何一种弱的行为保证,那么任何优化都将是N。egated.
由于数据的所有成员都是基本类型,data2
将获得精确的“逐位拷贝”数据的所有成员的。因此,data2.b
的值将与data.b
的值完全相同。然而,data.b
的确切值无法预测,因为您并没有显式地初始化它。它将取决于为数据分配的内存区域中的字节值。。那个结构不是POD(普通的旧数据)?这意味着将使用默认值初始化成员?这是一个疑问,不是这个案子的肤浅副本吗?除非在复制的结构中访问未初始化的成员,否则会出现什么问题?@KevinKouketsu我为需要普通/POD类型的情况添加了一个条件。@TruthSeek标准说它是未定义的行为。AndreySemashev在回答中解释了(非成员)变量通常为未定义行为的原因。基本上,它是为了支持具有未初始化的陷阱表示
void test(unsigned char *arr, int n)
{
q temp;
for (int i=0; i<n; i++)
{
int it = arr[i];
x.dat[index] = i;
y.dat[index] = i;
}
}