C++ 对象并集与指针并集

C++ 对象并集与指针并集,c++,c++11,C++,C++11,如果我有两个并线结构: struct A { A() {} ~A() {} union { vector<int> vi; vector<double> db; }; }; 结构A{ A(){} ~A(){} 联合{ 向量vi; 矢量分贝; }; }; 及 结构B{ 联合{ 向量*vi; 向量*db; }; }; 我明白我必须以不同的方式与他们合作,例如: A a; new (&a.vi) ve

如果我有两个并线结构:

struct A {
    A() {}
    ~A() {}
    union {
        vector<int> vi;
        vector<double> db;
    };
};
结构A{ A(){} ~A(){} 联合{ 向量vi; 矢量分贝; }; }; 及

结构B{ 联合{ 向量*vi; 向量*db; }; }; 我明白我必须以不同的方式与他们合作,例如:

A a;
new (&a.vi) vector<int>;
A;
新的(&a.vi)载体;
vs

B;
b、 vi=新向量();
除此之外,将第一种方法(
无限制联合
)用于第二种方法(仅保留指向当前向量的指针)是否有任何优势?或者它们在功能和性能方面是相同的,唯一不同的是我如何使用它们


编辑:原始代码是没有编译的最简单示例,我在结构中添加了
A(){}
~A(){}
,以使其正确且可编译。

通常使用值或指针之间的区别是,如果使用指针,则必须管理所有权。拥有成员意味着成员类将在析构函数中自动销毁它,并在复制/移动构造函数和赋值运算符中复制它

但是,当使用不受限制的联合时,编译器不会为联合成员中非平凡的函数生成

std::vector
的情况下,这些函数包含了几乎所有的特殊成员函数

这意味着您必须自己定义这些函数,无论您使用的是成员(因为编译器不会为您这样做)还是指针(因为如果您使用
new
,指针的默认所有权不是您想要的)

明显的区别在于成员是以单独的分配方式驻留在堆上,还是驻留在对象本身中,这对于
vector
s可能不那么重要,因为大多数对象都将驻留在堆上


就我个人而言,除非我有很好的理由,否则我会避免使用不受限制的联合,节省一个
向量的空间(三个指针)可能还不够好。

通常使用值或指针之间的区别是,如果使用指针,就必须管理所有权。拥有成员意味着成员类将在析构函数中自动销毁它,并在复制/移动构造函数和赋值运算符中复制它

但是,当使用不受限制的联合时,编译器不会为联合成员中非平凡的函数生成

std::vector
的情况下,这些函数包含了几乎所有的特殊成员函数

这意味着您必须自己定义这些函数,无论您使用的是成员(因为编译器不会为您这样做)还是指针(因为如果您使用
new
,指针的默认所有权不是您想要的)

明显的区别在于成员是以单独的分配方式驻留在堆上,还是驻留在对象本身中,这对于
vector
s可能不那么重要,因为大多数对象都将驻留在堆上

就个人而言,除非我有很好的理由,否则我会避免使用不受限制的并集,节省一个
向量的空间(三个指针)可能还不够好

我在
A
struct中添加了
A(){}
~A(){}
,以使其正确且可编译

添加构造函数和析构函数可以使代码可编译,但不能使其正确。原始示例中固有的问题仍然存在:编译器不知道如何处理
联合后的内存

两个向量都管理自己的内存
vi
管理指向
int
的指针,而
db
管理指向
double
的指针。两个向量都放在内存中的同一位置,因此它们的指针是共享的。当分配、复制或销毁
A
时,编译器不知道调用-A::vi
A::db
的函数是谁

虽然您可以通过定义资源管理的所有特殊函数(构造函数/复制构造函数/移动构造函数/析构函数)使其正常工作,但这是一个非常重要的练习,会导致非常脆弱的代码。问题在于,每次向
联合添加新成员时,代码都必须更改,但编译器无法提醒您。旧代码可以编译,但一旦分配新成员并复制包含它的联合,就会导致未定义的行为

我在
A
struct中添加了
A(){}
~A(){}
,以使其正确且可编译

添加构造函数和析构函数可以使代码可编译,但不能使其正确。原始示例中固有的问题仍然存在:编译器不知道如何处理
联合后的内存

两个向量都管理自己的内存
vi
管理指向
int
的指针,而
db
管理指向
double
的指针。两个向量都放在内存中的同一位置,因此它们的指针是共享的。当分配、复制或销毁
A
时,编译器不知道调用-A::vi
A::db
的函数是谁

虽然您可以通过定义资源管理的所有特殊函数(构造函数/复制构造函数/移动构造函数/析构函数)使其正常工作,但这是一个非常重要的练习,会导致非常脆弱的代码。问题在于,每次向
联合添加新成员时,代码都必须更改,但编译器无法提醒您。旧代码可以编译,但一旦分配新成员并复制包含它的联合,就会导致未定义的行为。

A a;
new (&a.vi) vector<int>;
B b;
b.vi = new vector<int>();