C++ 中的可扩展自动类注册

2024-01-09

C++ 中的自动类注册是一项常见任务,也是 StackOverflow 上的一个常见问题:

在对象工厂中注册对象创建者 https://stackoverflow.com/questions/1310214/register-an-object-creator-in-object-factory

以某种方式在列表中注册我的课程 https://stackoverflow.com/questions/1691473/somehow-register-my-classes-in-a-list

使用宏自动注册对象创建器函数 https://stackoverflow.com/questions/6137706/automatic-registration-of-object-creator-function-with-a-macro

C++派生类型的自动工厂注册 https://stackoverflow.com/questions/9975672/c-automatic-factory-registration-of-derived-types

基本目标是使用某些注册表或工厂自动注册类,以便稍后可以对每个类进行一些工作。

这是一项成熟的技术,被 Google Test 等库使用(http://code.google.com/p/googletest http://code.google.com/p/googletest),它会自动注册Test类的子类,以便每个测试都可以在测试执行过程中自动实例化并运行。

注册可以通过实例化一个静态注册器类(其构造函数执行注册)来完成,或者通过巧妙地使用 CRTP 并将注册代码放入基类构造函数中,或者您喜欢的任何方式(上面的链接提供了几种不同的可能技术)。

然而,当我实现这些技术中的任何一种时,我发现它们的扩展性非常差。如果我在 Google Test 中有 10,000 个 TEST 宏调用,编译和链接研磨就会停止(MSVC 2010)并且二进制大小会爆炸。如果我以另一种方式实现这一点,使用 10,000 个带有静态注册器的子类,我会看到相同的行为。

例如,考虑一个简化的例子:

#include <iostream>
#include <string>

class Base {

    public:

        Base( const std::string& Name_ ) : Name( Name_ ) { ; }
       ~Base() { ; }

        virtual std::string GetName() const { return Name; }
        virtual void DoSomething() = 0;

    private:

        std::string Name;

};

class Registry {

    public:

        static Registry& GetInstance() {
            static Registry* Instance = new Registry();
            return *Instance;
        }

        void Register( const Base* b ) {
            std::cout << "Registered class " << b->GetName() << std::endl;
        }

    private:

        Registry()  { ; }
       ~Registry()  { ; }

};

class Registrar {

    public:

        Registrar( const Base* b ) {
            Registry::GetInstance().Register( b );
        }

       ~Registrar() { }

};


#define  REGISTER( CLASS )                                          \
    class CLASS : public Base {                                     \
        public:                                                     \
            CLASS( const std::string& Name ) : Base( Name ) { ; }   \
            virtual void DoSomething();                             \
        private:                                                    \
            static Registrar m_Registrar;                           \
    };                                                              \
    Registrar CLASS::m_Registrar( new CLASS( #CLASS ) );            \
    void CLASS::DoSomething()


int main( int argc, char** argv )
{
    return 0;
}


REGISTER( Class1 )
{
    std::cout << "Doing something in Class1" << std::endl;
}

REGISTER( Class2 )
{
    std::cout << "Doing something in Class2" << std::endl;
}

[...]

总共 10000 个自动生成的 REGISTER 调用。

是否存在无法很好扩展的根本原因?编译器会因为 10000 个类而窒息吗?在 MSVC 2010 下,在相当快的机器上编译上述内容大约需要两分钟,并生成大小超过 5 MB 的二进制文件。如果我对 Google Test 进行类似的操作,我会看到相同的结果。


用 C++ 编写 Java 代码很少能奏效。所有这些堆分配可能都会影响性能(就像在 Java 中一样,但 Java 启动速度太慢以至于没有人会注意到)。使用静态对象,并且不要放置Registrar对象到每个生成的类中;这只是浪费时间和空间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 中的可扩展自动类注册 的相关文章

  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况

随机推荐