C/C++通过__attribute__((constructor))函数属性实现自动注册机制

发布于:2025-07-12 ⋅ 阅读:(16) ⋅ 点赞:(0)

C/C++


文章目录


前言

代码中经常看到类是以下的宏定义,用于在程序启动时自动注册元数据信息映射:

宏名称和参数:

#define EMPLACE_METADATA_INFO_MAPPING(type, catagory, name, proxy_name) \
    __attribute__((                                                     \
        constructor)) void RegisterMetaDataInfo##proxy_name##name() {   \
        getMetaDataInfoMapping()[type] = {                              \
            catagory, #name, #proxy_name};                              \
    }

宏接受四个参数:
type:通常是一个类型标识符,作为映射的键。
catagory(应该是category的拼写错误):表示类别信息。
name:元数据的名称。
proxy_name:代理名称。
宏展开后的代码结构:

__attribute__((constructor)) void RegisterMetaDataInfo##proxy_name##name() {
    getMetaDataInfoMapping()[type] = {
        catagory, #name, #proxy_name
    };
}

这个宏的作用是在程序启动时,自动调用一个注册函数,将指定类型type对应的元数据信息(类别、名称、代理名称)存入一个全局映射中,方便后续通过type快速查找对应的元数据。这样设计可以实现自动注册机制,减少手动调用注册函数的麻烦。

关键点说明:

attribute((constructor)):这是GCC和Clang编译器的一个函数属性,表示该函数会在main()函数执行之前自动调用,通常用于初始化工作。
RegisterMetaDataInfo##proxy_name##name:这是函数名,使用了宏拼接操作符##,将proxy_name和name拼接到函数名中,确保每个注册函数名称唯一,避免重名。
getMetaDataInfoMapping():这是一个函数,返回一个映射(比如std::map或std::unordered_map),用于存储元数据信息。
[type] = { catagory, #name, #proxy_name }:将一个结构体或类似的数据赋值给映射中type对应的元素。这里用到了#操作符,将宏参数name和proxy_name转换成字符串字面量。

测试

下面编写一个测试用例:

#include <iostream>
#include <string>
#include <unordered_map>

// 定义一个结构体来存储元数据信息
struct MetaDataInfo {
    std::string category;
    std::string name;
    std::string proxy_name;
};

// 返回一个全局的映射,用于存储元数据
std::unordered_map<int, MetaDataInfo>& getMetaDataInfoMapping() {
    static std::unordered_map<int, MetaDataInfo> mapping;
    return mapping;
}

// 你的宏定义,修正了拼写错误 category
#define EMPLACE_METADATA_INFO_MAPPING(type, category, name, proxy_name) \
    __attribute__((constructor)) void RegisterMetaDataInfo##proxy_name##name() { \
        getMetaDataInfoMapping()[type] = { category, #name, #proxy_name }; \
    }

// 使用宏注册几个元数据
EMPLACE_METADATA_INFO_MAPPING(1, "CategoryA", MyData, ProxyX)
EMPLACE_METADATA_INFO_MAPPING(2, "CategoryB", OtherData, ProxyY)
EMPLACE_METADATA_INFO_MAPPING(3, "CategoryC", MoreData, ProxyZ)

int main() {
    auto& mapping = getMetaDataInfoMapping();

    for (const auto& [key, info] : mapping) {
        std::cout << "Type: " << key << "\n";
        std::cout << "  Category: " << info.category << "\n";
        std::cout << "  Name: " << info.name << "\n";
        std::cout << "  Proxy Name: " << info.proxy_name << "\n";
        std::cout << "----------------------\n";
    }

    return 0;
}

说明:

定义了一个MetaDataInfo结构体,存储类别、名称和代理名称。
getMetaDataInfoMapping()返回一个静态的全局映射,存储type到MetaDataInfo的映射。
使用宏EMPLACE_METADATA_INFO_MAPPING注册了3条元数据,分别对应不同的type。
attribute((constructor))保证注册函数在main()之前自动执行,完成注册。
main()函数中遍历映射并打印所有注册的元数据信息。
你可以直接编译运行这段代码,看到自动注册的元数据被正确存储和访问。需要注意的是,这个宏和代码在GCC或Clang下支持__attribute__((constructor)),在其他编译器(如MSVC)可能需要其他方式实现自动初始化。

总结

这个宏的作用是在程序启动时,自动调用一个注册函数,将指定类型type对应的元数据信息(类别、名称、代理名称)存入一个全局映射中,方便后续通过type快速查找对应的元数据。这样设计可以实现自动注册机制,减少手动调用注册函数的麻烦。


网站公告

今日签到

点亮在社区的每一天
去签到