17

在 C++ 中,您可以这样做:

static const char * [4] = {
   "One fish",
   "Two fish",
   "Red fish",
   "Blue fish"
};

...这为您提供了一个很好的只读数组数据结构,它在运行时不需要任何 CPU 周期来初始化,因为所有数据都已为您布局(在可执行文件的只读内存页面中)编译器。

但是如果我宁愿使用不同的数据结构而不是数组呢?例如,如果我希望我的数据结构能够通过键快速查找,我必须执行以下操作:

static std::map<int, const char *> map;

int main(int, char **)
{
   map.insert(555, "One fish");
   map.insert(666, "Two fish");
   map.insert(451, "Red fish");
   map.insert(626, "Blue fish");

   [... rest of program here...]
}

...由于地图数据结构在运行时被填充,这不太优雅且效率较低,即使所有必要的数据在编译时都是已知的,因此(理论上)可以完成这项工作。

我的问题是,在 C++(或 C++11)中有什么方法可以创建一个只读数据结构(例如地图),其数据完全在编译时设置,因此预先填充并准备好在运行时,数组的方式可以是什么?

4

4 回答 4

8

如果您想要地图(或集合),请考虑使用存储为数组的二叉树。您可以在调试版本中断言它在运行时已正确排序,但在优化版本中,您可以假设一切都已正确安排,然后可以执行与 std::map 中相同的二进制搜索操作,但使用底层storage 是一个数组。只需编写一个小程序来为您堆积数据,然后再将其粘贴到您的程序中。

于 2013-03-19T02:26:53.557 回答
5

不容易,不。如果您尝试使用 来执行您的第一个示例malloc,显然它在编译时不起作用。由于每个标准容器都使用new(好吧,std::allocator<T>::allocate()但我们暂时假设它是new),我们不能在编译时这样做。

话虽如此,这取决于您愿意经历多少痛苦,以及您想推迟多少编译时间。您当然不能仅使用标准库功能来做到这一点。boost::mpl另一方面使用...

#include <iostream>

#include "boost/mpl/map.hpp"
#include "boost/mpl/for_each.hpp"
#include "boost/mpl/string.hpp"
#include "boost/mpl/front.hpp"
#include "boost/mpl/has_key.hpp"

using namespace boost::mpl;

int main()
{
    typedef string<'One ', 'fish'> strone;
    typedef string<'Two ', 'fish'> strtwo;
    typedef string<'Red ', 'fish'> strthree;
    typedef string<'Blue', 'fish'> strfour;

    typedef map<pair<int_<555>, strone>,
        pair<int_<666>, strtwo>,
        pair<int_<451>, strthree>,
        pair<int_<626>, strfour>> m;

    std::cout << c_str<second<front<m>::type>::type>::value << "\n";
    std::cout << has_key<m, int_<666>>::type::value << "\n";
    std::cout << has_key<m, int_<111>>::type::value << "\n";
}
于 2013-03-19T04:16:13.147 回答
2

值得一提的是,您的问题源于您使用 map 的事实。地图经常被过度使用。地图的替代解决方案是排序的向量/数组。地图仅在用于存储长度未知的数据时或(并且仅在有时)数据频繁更改时才变得比地图“更好”。

函数 std::sort, std::lower_bound/std::upper_bound 是您所需要的。如果您可以自己对数据进行排序,则只需要一个函数,lower_bound,并且数据可以是const。

于 2013-03-19T10:01:26.193 回答
0

是的,C++11 允许大括号初始值设定项:

std::map<int, const char *> map = {
  { 555, "One fish" },
  { 666, "Two fish" },
  // etc
};
于 2013-03-19T02:27:50.913 回答