c – 接口范例性能(动态绑定与泛型编程)

虽然它们的核心动态绑定和模板是根本不同的东西,但它们可用于实现相同的功能.

代码示例(仅供参考)

A)动态绑定

namespace DB {
  // interface
  class CustomCode {
    public:
      virtual void operator()(char) const = 0;
  };
  class Lib {
    public:
      void feature(CustomCode const& c) {
        c('d');
      }
  };

  // user code
  class MyCode1 : public CustomCode {
    public:
      void operator()(char i) const {
        std::cout << "1: " << i << std::endl;
      }
  };
  class MyCode2 : public CustomCode {
    public:
      void operator()(char i) const {
        std::cout << "2: " << i << std::endl;
      }
  };

  void use() {
    Lib lib;
    lib.feature(MyCode1());
    lib.feature(MyCode2());
  }
}

B)通用编程

namespace GP {
  //interface
  template <typename CustomCode> class Lib {
    public:
      void feature(CustomCode const& c) {
        c('g');
      }
  };

  // user code
  class MyCode1 {
    public:
      void operator()(char i) const {
        std::cout << "1: " << i << std::endl;
      }
  };
  class MyCode2 {
    public:
      void operator()(char i) const {
        std::cout << "2: " << i << std::endl;
      }
  };

  void use() {
    Lib<MyCode1> lib;
    lib.feature(MyCode1());
    //lib.feature(MyCode2());  <-- illegal
  }
}

一些想法

虽然这些范例并不相同并且各有优缺点(A更强大(参见MyCode2)而B对用户更灵活)但它们都允许实现相同的功能(虽然上面提到的限制适用).

无论如何,理论上(TM)A由于虚函数的间接性而在运行时稍慢,而B提供了一些很好的优化机会,因为方法可以内联(当然你没有间接).
但是,我经常觉得A有点自我记录,因为你必须实现一个清晰的界面(通常由多个方法组成),而B则更无政府主义(这意味着它的灵活性).

核心

>这些范例是否有任何一般结果/比较研究?
>加速是否显着?
>编译时间怎么样?
>对于大型系统中的接口,有哪些设计含义(我主要使用A作为我的模块间接口,到目前为止我还没有真正做过大型项目)?

编辑

注意:说“动态绑定更好,因为它更强大”根本不是一个答案,因为前提条件是你有两种方法适用的情况(否则没有自由选择 – 至少不合理) .

解决方法

Are there any general results / comparative studies of these paradigms?

从我所看到的,许多证据的例子可以在文章和出版物中找到.你最喜欢的c书应该提供几个演示;如果你没有这样的资源,你可能想要阅读现代C设计:应用的通用编程和设计模式 – A. Alexandrescu.但是,没有特定的资源可以直接回答您的问题.同样,结果会因实现和编译器而异 – 甚至编译器设置也会极大地影响这种测试的结果. (回答你的每个问题,虽然这不符合这个具体问题的答案).

Is the speed-up significant?

简短回答:这取决于.

在您的示例中,编译器实际上可以使用静态分派甚至内联虚函数调用(编译器可以看到足够的信息).我现在要将响应从一个简单的例子(特别是OP)转移到更大,更复杂的程序.

扩展’依赖’:是的,加速可以从不可测量到巨大.你必须(并且可能已经)意识到编译器可以通过泛型在编译时提供大量的信息.然后,它可以使用此信息更准确地优化您的程序.一个很好的例子就是使用std :: array vs std :: vector.向量在运行时增加了灵活性,但成本可能非常高.向量需要实现更多的调整大小,动态分配的需求可能是昂贵的.还有其他不同之处:数组的后备分配不会改变(优化),元素数量是固定的(优化),而且在很多情况下都不需要调用new.

你现在可能会认为这个例子明显偏离了原来的问题.在很多方面,它实际上并没有那么不同:随着复杂程度的扩展,编译器对程序的了解越来越多.这个信息可以删除程序的几个部分(死代码)并使用std :: array作为示例,类型提供的信息足以使编译器可以轻松地说“哦,我看到这个数组的大小是七个元素,我将相应地展开循环“并且您将获得更少的指令并且将消除错误预测.还有更多内容,但在数组/向量的情况下,我看到当从向量转换为类似于数组的接口时,优化程序的可执行文件大小减少到20%.同样,代码可以执行几倍的速度.事实上,一些表达式可以完全在编译时计算.

动态调度仍有其优点,如果正确使用,使用动态调度也可以提高程序的速度 – 您真正需要学习的内容归结为决定何时优先于另一个.类似于具有许多变量的巨大函数无法非常有效地优化(实际程序中所有模板扩展的结果),虚拟函数调用在许多情况下实际上可以是更快,更清晰的方法.因此,它们是两个独立的功能,你需要一些练习来确定什么是正确的(许多程序员不会花时间去学好这个).

总之,它们应被视为单独的特征,适用于不同的场景.这些应该(imho)与现实世界中的实际重叠要少得多.

What about compilation time?

使用模板,开发过程中的编译和链接时间可能非常高.每次标题/模板更改时,您都需要对所有依赖项进行编译 – 这通常可以成为支持动态调度的重要福音.如果您提前计划并适当地构建,您当然可以减少这一点 – 了解如何通过模板掌握更难的主题.使用模板,您不仅可以增加大型构建的频率,还可以增加大型构建的时间和复杂性. (更多说明如下)

What are the design implications of either for interfaces in larger systems (I mainly used A for my inter-module interfaces and I haven’t done really really big projects so far)?

这真的取决于你的计划的期望.我每年写虚拟的东西(还有很多其他的).在其他方法中,模板变得越来越普遍.老实说,我不明白B是如何“无政府主义”的.对我来说,A有点不合时宜,因为有很多合适的选择.它最终是一个设计选择,可以很好地考虑很好地构建大型系统.一个好的系统将使用该语言功能的健康组合.历史证明在这个讨论中没有必要编写一个非常重要的程序,但是所有功能都被添加了,因为有些人在某些特定用途中看到了更好的选择.你还应该期望lambdas在一些(不是全部)团队/代码库中用超过50%的当前用途来替换虚拟用户.

推广:

如果使用正确,>模板的执行速度会明显加快.
>要么可以产生更大的可执行文件.如果使用正确且可执行文件大小很重要,那么编写器将使用多种方法来减少可执行文件的大小,同时提供良好的可用接
>模板可以变得非常复杂.学习浏览并解释错误消息需要时间.
> templates将多个错误压入编译域.就个人而言,我赞成编译错误而不是运行时错误.
>通过虚拟减少编译时间通常很简单(虚拟属于.cpp).如果您的程序很大,那么经常更改的大型模板系统可以快速发送您的重建时间并计算在屋顶上,因为会有很多模块间可见性和依赖性.
>使用较少编译文件的延迟和/或选择性实例化可用于减少编译时间.
>在较大的系统中,您必须更加体贴地为您的团队/客户强制进行重要的重新编译.使用虚拟化是一种最小化这种方法的方法.同样,将在cpp中定义更高比例的方法.替代方案当然是您可以隐藏更多的实现,或者为客户提供更具表现力的方式来使用您的接口.
>在较大的系统中,模板,lambda / functor等实际上可用于显着减少耦合和依赖性.
>虚拟增加依赖性,通常变得难以维护,膨胀界面,并成为结构上笨拙的野兽.以模板为中心的库倾向于颠倒该优先级.
>所有方法都可以用于错误的原因.

底线一个大型,精心设计的现代系统将有效地同时使用许多范例.如果你现在大部分时间都在使用虚拟机,你就是(imo)做错了 – 特别是如果你有时间去吸收c 11仍然是方法,如果速度,性能和/或并行性也是重要的问题,然后模板和lambdas值得成为你的亲密朋友.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读315次。之前用C语言编过链表,这几天突然想用C++编一下链表,搞了大半天才搞出来,所以就赶紧整理一下记录下来,省的万一时间长了找不到代码哈哈。一、链表代码1、Node.h文件代码#pragma onceclass Node{public: int ID; char alph; Node* next; Node(int ID,char alph); ~Node();private:..._if(current->id==id)
文章浏览阅读219次。碰到问题就要记录下来,防止遗忘吧。文章目录一、VS中的命令行参数二、内联函数和宏三、初始化和赋值一、VS中的命令行参数今天在运行代码的时候,碰都了下面的情况: // 解析命令行参数 if (pcl::console::find_argument (argc, argv, "-h") >= 0) { printUsage (argv[0]); return 0; }..._"if (pcl::console::find_argument(argc, argv, "-f") >= 0)怎么输入参数"
文章浏览阅读1.8k次,点赞11次,收藏37次。因为自己对决策树的机制非常的好奇,所以就研究了一下决策树的ID3算法,在这也做一篇笔记记录一下过程。文章目录一、什么是决策树?二、信息增益2.1信息熵2.1.1定义2.1.2演变2.2信息增益三、ID3算法实现四、小结一、什么是决策树?这个问题是我从一开始就有的疑问,什么是决策树?在看了一些资料之后,因为没有看到书上给出具体定义,所以按照我自己的理解决策树就是通过一个个“决策”而构建的一种树状结构,而且决策树的整个处理机制非常类似于我们人类在面临决策问题时的处理机制,这也可能就是其名字的由来。决_c++id3
文章浏览阅读492次。C++ 设计模式之策略模式
文章浏览阅读683次。我也算是个C++的小白,对于C++中的谓语我第一时间就想到了C#中的委托,但两者又不尽相同,所以想写一篇笔记记录一下。文章目录一、什么是谓语?二、使用谓语一、什么是谓语?谓语是一个可调用的表达式,其返回的结果可以作为条件的值,在C++中其实就是向算法传递函数。这和C#中的委托的概念其实是一样的,都是将函数作为参数进行传递。C++标准库中的谓语主要有两类:一元谓语和二元谓语,也就是有的算法只能..._谓语句 c++
文章浏览阅读225次。又看了一遍操作符的东西,感觉之前对操作符的理解还停留在很浅的认知上(仅仅会用哈哈),所以做一下笔记来加深一下印象。文章目录一、为什么会有操作符重载?二、操作符重载作用的对象一、为什么会有操作符重载?如果要回答这个问题,我们其实应该仔细想一下如果没有操作符重载会怎样呢?这其实很容易就联想到了C语言,因为他就没有操作符重载这一说。虽然C语言中没有类class这一概念,但是他有着和类及其相似的结构..._6-6 我的朋友 - c/c++ 操作符重载分数 15作者 海洋饼干叔叔单位 重庆大学实现frie
文章浏览阅读216次。因为之前碰到了很多关于C++上的问题,现在整理并记录一下。文章目录一、引用一、引用在C++中,引用就是给对象起了另一个名字,也就是“对象别名”。感觉和什么东西很相似,仔细一想不就是类型别名“typedef”吗哈哈。它其实是和原对象形成了一种绑定的一种关系,..._vc++6.0报错:returning address of local
文章浏览阅读565次。因为一直好奇预处理器的工作机制,所以就查了查书,做一下自己看完书之后的笔记。文章目录一、预处理器的作用一、预处理器的作用_c语言预处理器作用
文章浏览阅读1.8k次,点赞3次,收藏10次。最近特别查阅了一下关于C++文件的输入/输出的资料,整理了一下就写一下笔记。文章目录一、什么是流二、什么是缓冲区三、代码实现文件IO3.1 使用文件流对象读取数据3.2重定向一、什么是流当前的计算机具有很多种设备,但是无论是哪种设备都要与数据和信息进行打交道,所以这就牵扯到设备与数据之间的I/O操作。而每种设备又有着不同的特性和操作协议,由于过于复杂,所以我们一般是不会和这些通信细节打交道的..._c++ inpath
文章浏览阅读4.8k次,点赞6次,收藏29次。因为要使用到C++的动态链接库,所以就特意网上找了一下资料实现了一下。文章目录一、lib与dll文件二、创建dll文件三、dll隐式链接四、显式链接五、小结一、lib与dll文件之前我一直以为动态链接库就是指dll文件,这也是C#给我造成的一种印象,因为在C#中建立的类库文件都是dll文件,而且只要简单引用就可以了,但是C++却并不是这样的,这可能是因为C#隐藏了一些细节的缘故吧。在C++中共有两种库模式,一种是包含lib和dll两种文件,这种情况下其中的lib文件包含了函数所在的dll文件和dl_c++调用动态链接库
文章浏览阅读973次。因为遇到了一这个操作符的问题,所以记录一下出现的问题*~*。一、问题描述二、产生原因因为也是第一次出现这个问题,所以就到网上查了一些资料和书籍,现在倒也大概理解这个错误出现的原因了。有时候举个例子可能更容易理解为啥会出现这个错误,就拿一本书中的例子来说一下,如下所示:template<class T> class NamedObject { public: NamedObject(std::string& nameVal, const T objectVal) __copy_assign报错
C语言中的单向链表可以解决数组和结构体在使用时的内存连续性问题,同时还能动态地调整长度。本文介绍了单向链表的结构和基本操作,并给出了一个简单的示例代码。
文章浏览阅读2.3k次。区分'0'、"0"、0、''_0和
文章浏览阅读5.8k次,点赞4次,收藏8次。C语言函数指针详解,微剖本质_c语言指针函数
数组指针和指针数组是代码中常见的定义形式。虽然它们的语法类似,但含义完全不同。对于一维数组而言,数组名即为首元素的地址,不需要取址即可赋值给指针。而对于二维数组,数组名代表首行元素的地址,可以看作是一个指针数组,需要使用取址操作。
文章浏览阅读297次。总结刚入门的新同学C语言编程常见的低级错误
文章浏览阅读1.5w次,点赞12次,收藏70次。C语言 数组指针详解_c语言数组指针
文章浏览阅读306次。cJson常用接口总结并测试_用于测试的json接口
本篇文章和大家了解一下C语言中pthread_exit()函数实现终止线程的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。多线程编程中,线程...
本教程操作系统:windows10系统、c99版本、DELL G3电脑。 C语言是一门强大的编程语言,它允许我们对不同的数据类型进行各种运算和操作。但是有时候,我们需要将一个数据类型转换为另一个数据类型。这就是强制类型转