使用联合作为树中的项类型,以便存储两种不同的数据类型
Use a union as a item-type in a tree in order to store two different data types
请考虑以下代码:
union tree_item
{
tree_item(std::valarray<double> const& point)
: point(point)
{ }
tree_item(unsigned coord, double coord_value)
: splitting_line({ coord, coord_value })
{ }
struct {
unsigned coord;
double coord_value;
} splitting_line;
std::valarray<double> point;
};
我们如何确保,如果一个tree_item
对象存储了一个point
, point
的析构函数被调用?我可以写
~tree_item() {
point.~valarray();
}
但是我认为,如果我们给coord
或coord_value
赋值,这会导致未定义的行为。
我想做的就是用tree_item
代替
T
template<typename T>
struct tree_node
{
tree_node(T const& item)
: item(item)
{ }
tree_node(T&& item)
: item(std::move(item))
{ }
bool is_leaf() const noexcept {
return !left && !right;
}
T item;
std::shared_ptr<tree_node<T>> left, right;
};
splitting_line
和point
是我想要存储在树中的两种类型的项。显然,我可以分别为splitting_line
和point
编写基类和派生类。然而,由于在这种情况下,我不想对这些项执行操作(我只想存储这些不同的类型),并且我需要使用dynamic_cast
或某种类型标志,这将使我的代码变得过于复杂。
那么,我该怎么办呢?
不应该使用union
,而应该使用一个类来处理拥有真正变体类型所需的更多功能:boost::variant
:
using tree_item = boost::variant<
splitting_line,
std::valarray<double>
};
variant
对象将确保根据存储的内容调用正确的析构函数。它还跟踪它所拥有的对象,这样你就可以对它执行类型安全的操作(这在你的union
上也是不可能的)。
这就是虚拟继承的作用。使用一个通用的基类型,可能称为tree_item_base
,并带有两个派生类型tree_item_point
和tree_item_splitting_line
。但是,tree_node
需要使用引用或自动指针类型。
如果你想在设计中使用不受限制的联合,为了调用正确的析构函数,你必须将联合内部的信息存储在其外部,例如在tree_node或其他类型的包装器类型中,这将在某些枚举中保留数据类型并调用正确的构造函数/析构函数。
我在gcc/clang上试过你的代码,稍微修改了一下,它实际上没有发出任何警告。
#include <functional>
#include <iostream>
#include <valarray>
union tree_item
{
tree_item(std::valarray<double> const& ppoint) : point(ppoint) {
//new (&point)std::valarray<double>(ppoint);
}
tree_item(unsigned coord, double coord_value)
: splitting_line({ coord, coord_value })
{ }
~tree_item(){
// cannot call point dtor here because we dont know if it was used
}
struct {
unsigned coord;
double coord_value;
} splitting_line;
std::valarray<double> point;
};
int main() {
std::valarray<double> point={1,2,3};
// constructed with std::valarray, destructor must be called manually
tree_item nn(point);
std::cout << nn.point[2];
nn.point.~valarray<double>();
tree_item nn2(1.0, 2.0);
return 0;
}
http://melpon.org/wandbox/permlink/02f5GI5WTTlLvprY 相关文章:
- 在C++中将函数压缩为两种方式
- 如何使映射键具有两种不同的数据类型?
- 两种访问I2C总线的方法有什么区别?
- 两种模板示例有什么区别?
- 如何构造可以调用和返回两种不同类型的模板
- 多维数组存储三种不同的数据类型?
- 这两种C++语法之间有什么区别?
- 为什么两种不同的对象初始化方式给出不同的输出
- std::cin 从控制台获取两种不同的变量类型,'storing'以后使用第二种类型?
- 定义类模板构造函数的两种方法之间的区别
- 初始化类的两种方法?
- C++ 一个函数,可以根据接受的值返回两种类型之一
- 如何检查程序员在C++中提供的两种不同格式的输入
- C++指针中的这两种类型的值分配有什么区别?
- 如何在c ++中以一行(水平)打印两个文件的数据?如给定的.这两种形式来自两个不同的文本文件
- 生成一个类Name_class并将两种数据类型存储在一个向量中
- 处理特征中两种存储布局的固定大小矩阵的连续向量
- 在 QModelIndex 中存储两种不同的类型
- C++如何在一个向量中存储两种数据类型
- 使用联合作为树中的项类型,以便存储两种不同的数据类型