В C ++ вы можете сделать это:
static const char * [4] = {
"One fish",
"Two fish",
"Red fish",
"Blue fish"};
… и это дает вам хорошую структуру данных массива только для чтения, которая не требует циклов ЦП для инициализации во время выполнения, потому что все данные были размещены для вас (на страницах памяти только для чтения исполняемого файла) компилятором.
Но что, если я предпочел бы использовать другую структуру данных вместо массива? Например, если бы я хотел, чтобы моя структура данных имела быстрый поиск по ключу, мне пришлось бы сделать что-то вроде этого:
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) создать структуру данных только для чтения (например, карту), чьи данные полностью настраиваются во время компиляции и, таким образом, предварительно заполнены и готовы к использованию в во время выполнения, каким может быть массив?
Не легко, нет. Если вы попытались сделать свой первый пример, используя 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";
}
Если вы хотите карту (или набор), рассмотрите вместо этого использование двоичное дерево хранится в виде массива. Вы можете утверждать, что он упорядочен во время выполнения в отладочных сборках, но в оптимизированных сборках вы можете просто предполагать, что все правильно организовано, а затем выполнять те же виды операций двоичного поиска, что и в std :: map, но с нижележащим хранилище является массивом. Просто напишите небольшую программу, чтобы накапливать данные для вас, прежде чем вставлять их в вашу программу.
Стоит отметить, что ваша проблема связана с тем, что вы используете карту.
Карты часто перегружены.
Альтернативным решением для карты является отсортированный вектор / массив. Карты становятся «лучше», чем карты, когда используются для хранения данных неизвестной длины или (и только иногда), когда данные часто изменяются.
Функции std :: sort, std :: lower_bound / std :: upper_bound — это то, что вам нужно.
Если вы можете сортировать данные самостоятельно, вам нужна только одна функция lower_bound, и данные могут быть постоянными.
Да, C ++ 11 позволяет инициализировать фигурные скобки:
std::map<int, const char *> map = {
{ 555, "One fish" },
{ 666, "Two fish" },
// etc
};