Использование map в C++ и предоставление функций-оболочек для использования в C
В MSVC6 мне нужно использовать map в C++ и предоставлять функции-оболочки, чтобы использовать их в c только для добавления, удаления и получения размера. Я хочу сделать это без использования каких-либо классов в C++. Это будет использоваться потоками, каждый поток будет иметь дескриптор структуры, который будет иметь void *
который будет передан в качестве параметра в функции оболочки C++, и я хочу, чтобы код C++ преобразовал это void *
на карту и делать операции. Я не могу конвертировать void *
к карте в C++ было бы полезно любое решение.
2 ответа
Я попробую, потому что мне нравится гадать:
Я предполагаю, что у вас есть функция, которая передается в функцию create thead, которая выглядит примерно так:
int callback(void* userdata);
Итак, давайте сделаем функцию обратного вызова для доступа к карте:
// In the header file: "my_callback.h" we first need to declare that this function will be used from a C file, this is so the compiler will name the function according to the C standard and not C++.
#ifdef __cplusplus
extern "C" {
#endif
// Declare your function:
int my_callback(void * map_handle);
#ifdef __cplusplus
extern "C" {
#endif
Теперь, в файле C++, убедитесь, что вы включили заголовочный файл:
#include "my_callback.h"
int my_callback(void * map_handle) {
// First, for convenience, let us define the map type
using mapType = std::map<std::string, int>;
// First cast the void * to a the correct map * pointer
mapType *mapPtr = static_cast<mapType*>(map_handle);
mapPtr->insert( "Test", 1 ); // Insert
cout << (*mapPtr)["Test"]; // read
// Or you can assign it to a reference to hide away the pointer syntax:
mapType & mapRef = *static_cast<mapType*>(map_handle);
mapRef.insert( "Test", 1 ); // Insert
cout << mapRef["Test"]; // read
// (...)
}
Есть несколько вещей, которые стоит отметить:
Нам разрешено использовать
static_cast
потому что вход являетсяvoid
Указатель, вы должны передавать адрес целевой карты, когда вы создаете поток, и статическое приведение к и затем из пустого указателя на тот же тип хорошо определено.Это никоим образом не потокобезопасно. При обращении к одному и тому же ресурсу из нескольких потоков следует соблюдать особую осторожность. Если вы намереваетесь иметь только одну карту и разрешить всем потокам обращаться к ней, вы должны включить мьютекс, чтобы гарантировать, что только один поток обращается к ней одновременно. Отличный способ сделать это - просто создать небольшую структуру, включающую карту и мьютекс:
struct map_n_mutex {mapType map; some_mutex_t mutex; // Не уверен, какой будет правильный тип мьютекса в Windows. };
На этапе инициализации вашего потока:
// Create map
map_n_mutex user_data;
// Create thread (I'm making this function up, use what you have been using)
create_thread( my_callback, &user_data); // pass a pointer to userdata
Если вы придерживаетесь этого подхода, помните, что вам нужно map_n_mutex
и не mapType
внутри функции обратного вызова.
Код C нужно будет получить void
указатель из кода C++, делает что-то вроде
void *get_map_from_cpp(); /* declare the function */
void *our_map = get_map_from_cpp();
где get_map_from_cpp()
будет определен (в C++) как что-то вроде;
#include <map>
#include <string>
extern "C" void *get_map_from_cpp()
{
std::map<std::string, float> *the_map = new std::map<std::string, float>;
return static_cast<void *>(the_map);
}
Это не останавливается там все же. Чтобы вставить значения в карту, нам нужно передать значения, например, в C
void insert_to_map(void *, const char *str, float f); /* declaration */
insert_to_map(our_map, "Everything", 42.0);
где insert_to_map()
также должен быть определен в C++, например как
extern "C" void insert_to_map(void *m, const char *str, float f)
{
std::map<std::string, float> *the_map;
the_map = static_cast< std::map<std::string, float> *>(m);
std::string the_str(str);
(*the_map)[the_str] = f;
}
Точно так же, retrieve_from_map()
может быть реализовано как
extern "C" float retrieve_from_map(void *m, const char *str)
{
std::map<std::string, float> *the_map;
the_map = static_cast< std::map<std::string, float> *>(m);
std::string the_str(str);
std::map<std::string, float>::const_iterator i = the_map->find(the_str);
if (i != the_map->end())
return i->second;
else
return 0.0f; // string not found in map, so return 0.0
}
Функции, вызываемые из C, должны предоставлять интерфейс только для C - это означает, что код C не может напрямую касаться типов C++. Во-вторых, сопоставление с C++ должно выполняться исключительно в коде C++, поскольку компилятор C не будет понимать конструкции. Это означает, что функции должны принимать или возвращать только те типы, которые имеют смысл в C, функции должны быть объявлены как extern "C"
для компилятора C++ (чтобы их можно было вызывать из C), а тело функции должно обрабатывать отображение типов C в C++.
Это зависит от совместимости компиляторов C и C++ (например, от одного поставщика, совместимого ABI и т. Д.).