如何在C++中编码大型复杂、恒定的数据结构
How to encode large complex, constant data structures in C++
过去,我使用 gcc 的 C99 风格的复合文字扩展来C++代码中对嵌套常量数据结构进行编码。下面是一个示例:
#include <iostream>
using namespace std;
struct Tree {
const char *name;
const Tree *left;
const Tree *right;
};
const Tree *const tree = (Tree []) {
"top", // name
(Tree[]) {
"left",
0,
0
},
(Tree[]) {
"right",
0,
0
}
};
static void dump(const Tree *tree) {
if (!tree) {
cout << "null";
return;
}
cout << tree->name << "(";
dump(tree->left);
cout << ", ";
dump(tree->right);
cout << ")";
}
int main(void) {
dump(tree);
cout << "n";
}
这个想法是对这些相当大的常量结构使用静态存储持续时间,初始化成本为零,并且除非需要,否则实际上不需要将任何内容分页到内存中。
然而,这在最新版本的 clang 中不再有效,最新的 OS X 将 clang 捆绑在名为"gcc"的名下。所以我需要一个不同的解决方案。
C++中最好的符合标准的成语是什么?
我不是特别想支付在这些结构中构建所有对象的成本,所以如果可以避免这种情况,那就太好了。
C++11 统一初始化语法应该有效:
const Tree* const tree = new Tree{"top",
new Tree{"left", nullptr, nullptr},
new Tree{"right", nullptr, nullptr}
};
否则,只需创建一个构造函数,将名称和子树作为参数。
如果你不希望结构被动态分配,你必须自己创建每个结构,然后使用例如地址运算符将它们链接在一起:
namespace
{
const Tree leftTree{"left", nullptr, nullptr};
const Tree rightTree{"right", nullptr, nullptr};
const Tree topTree{"top", &leftTree, &rightTree};
}
const Tree* const tree = &topTree;
如果大型复杂类型不是递归的,您可以简单地使用 constexpr 类型和统一初始化,无需任何技巧。
struct B { int i; };
struct C { double d; };
struct A {
B b;
C c;
};
constexpr A {B{1},C{3.2}};
但是,由于它是一棵树,并且您不能只拥有这样的递归类型(因为大小是无限的),因此需要技巧。我能想到两种方法。首先是使用指针或引用,以避免无限递归。
使用指针,您需要一种创建静态对象并获取指向它们的指针的方法。我认为C++没有任何可以让您在单个表达式中执行此操作的东西,因此需要为树中的每个节点进行声明,这并不方便。
对于引用,您需要某种方法来表示空节点(因为如果没有危险的黑客攻击,引用本身就无法为空)。下面是一个简单的实现:
struct Tree {
const char *name;
Tree const &left;
Tree const &right;
};
constexpr Tree Null{nullptr,Null,Null};
void print_tree(Tree const &t) {
if (&t == &Null) {
std::cout << "()";
return;
}
std::cout << '(' << t.name << ", ";
print_tree(t.left);
std::cout << ", ";
print_tree(t.right);
std::cout << ")";
}
constexpr Tree a {"a",
Tree{"b",
Null,
Tree{"d",Null,Null}},
Tree{"c",Null,Null}};
int main() {
print_tree(a);
}
避免递归的第二种方法是使用模板为每个不同的树结构生成不同的类型。
template<typename LTree, typename RTree>
struct Tree {
const char *name;
LTree left;
RTree right;
};
struct null_tree_t {};
constexpr null_tree_t null_tree{};
template<typename RTree>
struct Tree<null_tree_t, RTree> {
const char *name;
RTree right;
};
template<typename LTree>
struct Tree<LTree, null_tree_t> {
const char *name;
LTree left;
};
template<>
struct Tree<null_tree_t, null_tree_t> {
const char *name;
};
// C++14 return type deduction
template<typename LTree, typename RTree>
constexpr auto make_tree(const char *name, LTree ltree, RTree rtree) {
return Tree<LTree, RTree>{name, ltree, rtree};
}
template<typename LTree>
constexpr auto make_tree(const char *name, LTree ltree) {
return Tree<LTree, null_tree_t>{name, ltree};
}
template<typename RTree>
constexpr auto make_tree(const char *name, null_tree_t, RTree rtree) {
return Tree<null_tree_t, RTree>{name, rtree};
}
constexpr auto make_tree(const char *name) {
return Tree<null_tree_t, null_tree_t>{name};
}
template<typename LTree, typename RTree>
void print(Tree<LTree, RTree> const &tree) {
std::cout << '{' << tree.name << ", ";
print(tree.left);
std::cout << ", ";
print(tree.right);
std::cout << '}';
}
template<typename LTree>
void print(Tree<LTree, null_tree_t> const &tree) {
std::cout << '{' << tree.name << ", ";
print(tree.left);
std::cout << ", {}}";
}
template<typename RTree>
void print(Tree<null_tree_t, RTree> const &tree) {
std::cout << '{' << tree.name << ", {}, ";
print(tree.right);
std::cout << "}";
}
void print(Tree<null_tree_t, null_tree_t> const &tree) {
std::cout << '{' << tree.name << "}";
}
constexpr auto a = make_tree("a",
make_tree("b",
null_tree,
make_tree("d")),
make_tree("c"));
int main() {
print(a);
}
这样,叶节点的类型为 Tree<null_tree_t, null_tree_t>
,具有左子节点(即叶节点)的树为 Tree< Tree<null_tree_t, null_tree_t>, null_tree_t>
,具有左子节点的树具有右子节点(叶节点)为:
Tree<
Tree<
null_tree_t,
Tree<
null_tree_t,
null_tree_t>>,
null_tree_t>
等。
- 链表,反向函数,数据结构
- 如何使用set实现无序数据结构?
- 我们可以将数据永久保存为数据结构吗?
- C++中的可变长度数组/数据结构
- 用于存储由空格分隔的字符串的 C++/C 数据结构
- 通过 NIF 从C++返回自定义数据结构
- C++ 中具有 O(1) 搜索时间复杂度的数据结构
- 将数据插入一些复杂的数据结构-C
- QT:使用QVariant任意复杂的数据结构
- 最短路径的dijkstra算法的时间复杂度是否取决于所使用的数据结构?
- 具有恒定时间复杂度的无向图边的数据结构
- 如何在C++中编码大型复杂、恒定的数据结构
- 使用复杂的数据结构(向量数组的数组数组)时内存泄漏
- 我怎么知道一个数据结构按值搜索的平均复杂度
- 如何在c++中高效地从结构复杂的文件中读取二进制数据
- 是否有可能在cv::Mat中保存复杂的数据结构?
- 在c++中实现复杂的数据结构
- 复杂的数据结构,同时嵌入扩展 Python 与C++
- 给定数据结构的时间复杂度
- 数据结构- c++二叉搜索树-复杂类型