是使用未初始化的变量作为src对memcpy用C未定义行为?
void foo(int *to)
{
int from;
memcpy(to, &from, sizeof(from));
}
Run Code Online (Sandbox Code Playgroud) 我不太了解标准报价memcpy和union普通会员。
考虑代码:
struct Test{
union
{
void(*function_p)(void*);
void(*function_p_c)(const void*);
};
Test(const Test &other)
{
using std::memcpy;
memcpy(&function_p, &other.function_p, sizeof(function_p)); //?
memcpy(&function_p_c, &other.function_p_c, sizeof(function_p_c)); //??
}
};
int main(void)
{
Test t1; t1.function_p = NULL; //let it be NULL for c++98 sake
Test t2(t1); // is it safe? does this set new active member of union?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
因此,一个问题导致另一个问题:
上面的代码安全吗?还是UB排名第二/第一,memcpy取决于union所接触的成员用户?招募memcpy两个成员都太过分了吗?
如果不安全,那么我如何在没有一些活动联合成员标志的情况下实现复制构造函数?
正如C++标准(工作草案)所说:
9.5.1 [class.union]
在并集中,至多一个非静态数据成员可以在任何时间处于活动状态,也就是说,任何时候最多一个非静态数据成员的值都可以存储在并集中.[...] union的大小足以包含其中最大的非静态数据成员.每个非静态数据成员都被分配,就好像它是结构的唯一成员一样.union对象的所有非静态数据成员都具有相同的地址.
但我不知道如何识别哪个是工会的活跃成员,而且我没有用到足够深入标准来找到标准所说的内容,我试图弄清楚活动成员是如何设置的但我发现它是如何交换的:
9.5.4 [class.union]
[ 注意:通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员.- 注完 ] [ 实施例:考虑的对象
u的union type U类型的具有非静态数据成员米M和n类型的N.如果M有一个非平凡的析构函数并且N有一个非平凡的构造函数(例如,如果它们声明或继承虚函数),则可以安全地将u的活动成员切换m为n使用析构函数和placement new运算符,如下所示:Run Code Online (Sandbox Code Playgroud)u.m.~M(); new (&u.n) N;- 结束例子 ]
所以我的猜测是,工会的活跃成员是首先签署,使用,构建或放置新的成员; 但是这对于统一初始化变得有点棘手,请考虑以下代码:
union Foo
{
struct {char a,b,c,d;};
char array[4];
int integer;
};
Foo f; // default ctor
std::cout << f.a << f.b << f.c << f.d << '\n';
Run Code Online (Sandbox Code Playgroud)
哪个是上面代码的联合的活跃成员?是 …
说我有一个这样的工会
union blah {
foo f;
bar b;
};
Run Code Online (Sandbox Code Playgroud)
其中 和foo都是bar可简单复制的。这样做安全吗:
blah b;
foo f;
memcpy(&b, &f, sizeof(f));
Run Code Online (Sandbox Code Playgroud)
然后b.f作为活跃的工会成员使用?或者,我是否必须 memcpy 到特定的工会成员,如下所示:
memcpy(&b.f, &f, sizeof(f));
Run Code Online (Sandbox Code Playgroud)
我在实践中担心这一点的原因是因为我将不得不编写一个大致如下的函数:
template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
switch (c) {
case 0:
memcpy(&b.p0, &t, sizeof(t));
break;
case 1:
memcpy(&b.p1, &t, sizeof(t));
break;
// etc.
}
}
Run Code Online (Sandbox Code Playgroud)
但我宁愿能够跳过整个 switch 语句并只写这个:
template<int c>
void init_union(blah& b, typename type_family<c>::type const& t) {
memcpy(&b, &t, sizeof(t));
}
Run Code Online (Sandbox Code Playgroud)