gpt4 book ai didi

c++ - 包含非平凡成员 union 的类的构造函数和复制构造函数

转载 作者:可可西里 更新时间:2023-11-01 15:19:58 26 4
gpt4 key购买 nike

我正在尝试实现一个自定义变体类型,它使用 union 来存储各种不同类型的数据。在字段type_id中我打算存储union中存储的数据是哪种类型。 union 包含非平凡的成员。这是我当前的实现:

struct MyVariant {
enum { t_invalid, t_string, t_int, t_double, t_ptr, t_dictionary } type_id;
union {
int as_int;
double as_double;
std::string as_string;
std::unique_ptr<int> as_ptr;
std::map<int, double> as_dictionary;
};
};

我尝试创建一个 MyVariant 的实例,如下所示:

MyVariant v;

我收到错误消息:调用 MyVariant 的隐式删除默认构造函数。因此,我尝试手动实现构造函数,如下所示:

MyVariant() : type_id{t_int}, as_int{0} {}

这给了我类似的错误消息:尝试使用已删除的函数。接下来,我尝试实现以下构造函数:

MyVariant(int value) : type_id{t_int}, as_int{value} {}

并按如下方式构建我的实例:

MyVariant v{123};

=> 相同的错误消息:尝试使用已删除的函数

我也开始实现一个复制构造函数,它看起来像下面这样。但是,这当然对编译器错误没有帮助。

MyVariant::MyVariant(const MyVariant& other)
{
type_id = other.type_id;
switch (type_id) {
case t_invalid:
break;
case t_string:
new (&as_string) std::string();
as_string = other.as_string;
break;
case t_int:
as_int = other.as_int;
break;
case t_double:
as_double = other.as_double;
break;
case t_ptr:
new (&as_ptr) std::unique_ptr<int>(nullptr);
as_ptr = std::make_unique<int>(*other.as_ptr);
break;
case t_dictionary:
new (&as_dictionary) std::map<int, double>();
// TODO: copy values from other
break;
}
}

我使用 Xcode 和 Apple LLVM 6.1 作为编译器。

主要问题是:为什么我会收到编译器错误以及我必须如何修改我的代码才能使其编译?

另一个问题是:我对构造函数和复制构造函数的实现是否正确?

最佳答案

你的 union 有stringunique_ptrmap 类型的数据成员,所有这些都有重要的默认/复制/移动构造函数、复制/移动赋值运算符和析构函数。因此,对于您的 union ,所有这些都被隐式删除。

§9.5/2 [class.union]

... [ Note: If any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be user-provided or it will be implicitly deleted (8.4.3) for the union. —end note ]

所以你必须为你的 union 手动实现这些。至少,为了能够创建 MyVariant 的实例,该类需要是可构造和可破坏的。所以你需要

MyVariant() : type_id{t_int}, as_int{0} {}
~MyVariant()
{
switch(type_id)
{
case t_int:
case t_double:
// trivially destructible, no need to do anything
break;
case t_string:
as_string.~basic_string();
break;
case t_ptr:
as_ptr.~unique_ptr();
break;
case t_dictionary:
as_dictionary.~map();
break;
case t_invalid:
// do nothing
break;
default:
throw std::runtime_error("unknown type");
}
}

您的复制构造函数实现看起来有效,但我要做的不同之处在于,不是首先默认构造成员,然后从源对象复制,而是在放置新调用本身中复制构造。

MyVariant(const MyVariant& other)
{
type_id = other.type_id;
switch (type_id) {
case t_invalid:
break;
case t_string:
new (&as_string) auto(other.as_string);
break;
case t_int:
as_int = other.as_int;
break;
case t_double:
as_double = other.as_double;
break;
case t_ptr:
new (&as_ptr) auto(std::make_unique<int>(*other.as_ptr));
break;
case t_dictionary:
new (&as_dictionary) auto(other.as_dictionary);
break;
}

Live demo

请注意,如果 unique_ptr 成员处于事件状态,并且正在通过基类指针存储指向某个派生类实例的指针,那么您的复制构造函数实现将仅复制基类部分。

最后,除非您将此作为学习练习,否则我强烈建议您使用 Boost.Variant而不是自己滚动。

关于c++ - 包含非平凡成员 union 的类的构造函数和复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30492927/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com