首页 > 解决方案 > 如何在 C++ 中创建一个可以从 C 代码全局引用的对象?

问题描述

我有一个 C 语言的大型程序,我想将某些 C++ 对象与地图等一起使用。我关注了这篇关于如何从 C 调用 C++ 的帖子,我的两个 C++ 看起来像这样。

///map.cc
#include "map.h"

void* createMap()
{
    std::map<int,int> *m = new std::map<int,int>();
    return static_cast<void*>(m);
}
void putInMap(int key, int value, void* opaque_map_ptr){
    std::map<int,int> *m = static_cast<std::map<int,int>*>(opaque_map_ptr);
    m->insert(std::pair<int,int>(key,value));
}

//map.h
 #ifdef __cplusplus
 #define EXTERNC extern "C"
 #else
 #define EXTERNC
 #endif


EXTERNC void* createMap();

EXTERNC void putInMap(int key, int value, void* opaque_map_ptr);

我不清楚的是,如果我在我的 C 程序中执行以下调用,我如何确定我的 Map 存在以及如何使其成为全球性的?我是否只是将相应的指针设为全局?

#include "map.h"
//How do I let everyone use this map
void* ptr = createMap();

标签: c++cglobalextern

解决方案


//How do I let everyone use this pointer
void* ptr = createMap();

不是通过使用初始化程序声明一个全局对象= createMap(). C 不允许 C++ 具有的那种全局变量的动态初始化。指针必须由常量表达式初始化。如果你想createMap()在 C 中调用它只能在main输入之后发生,并且函数调用是显式的。

通常的模式是提供一个执行延迟初始化并返回指针的函数。

void *globalMap() {
    static void *ptr = NULL;
    if (!ptr)
        ptr = createMap();
    return ptr;
}

然后可以使用调用代码globalMap()来获取指向该对象的共享指针。如果需要“类对象”语法,则可以使用宏来包装函数调用

#define globalPtr globalMap()

这方面的一个标准示例可以通过errno.

必须提到的另一件事是我写了一个非常幼稚globalMap()的,因为指针分配不是线程安全的。使其线程安全并非不可能,但代码会稍微复杂一些。您可以由 C++ 编译器隐式完成(C++11 及更高版本)。该技术是所谓的 Meyers Singleton

extern "C" void *globalMap() {
    static std::map<int, bool> m;
    return &m;
}

就是这样。C++ 编译器将对其进行检测,使其m仅初始化一次并且没有竞争条件。


最后一点,不要忘记您必须在 ABI 边界上处理 C++ 异常!在正确的位置使用一些说明符使它们全部致命noexcept是一种方法,或者将它们转换为可能返回到 C 代码进行检查的错误。无论哪种方式,都不要忽视它们的存在。


推荐阅读