【问题标题】:Getters and Setters. Is there performance overhead?吸气剂和二传手。有性能开销吗?
【发布时间】:2012-12-13 05:16:57
【问题描述】:

我的 C++ 项目中有一个粒子系统引擎,粒子本身只是没有函数的变量结构。目前,每个粒子 (Particle) 通过直接访问其变量从其父类 (ParticleSystem) 更新。例如

particle.x += particle.vx;

然而,我正在辩论使用这样的 getter 和 setter:

particle.setX( particle.getX()+particle.getVX() );

我的问题是:与直接访问数据相比,调用 getter 和 setter 是否有任何性能开销?

毕竟,我确实有很多很多粒子要更新...

【问题讨论】:

  • setter/getter 主要是为了代码的可读性/可维护性。调用函数会比直接访问数据有性能开销。
  • Getter 和 setter 仅用于封装数据和对其的访问。没有性能开销,简单的 getter 和 setter 由编译器内联。
  • @habeebperwad:我无法想象它们是如何提高可读性的,但它们确实使更改实现变得更容易。
  • @MartinKristiansen:是的,你希望如此,而且你大部分时间都是对的,但并非总是如此。最好检查一下您是否在对性能至关重要的紧密循环中调用函数。
  • @All。显然,性能开销不会很大。但是在比较调用函数和直接数据访问时,我们可以看出直接数据访问会更快,即使开销不是很大。

标签: c++ performance getter-setter


【解决方案1】:

Setter 和 getter 在未优化时会产生性能开销。它们几乎总是在进行链接时间优化的编译器上进行优化。而在不知道的编译器上,如果他们知道函数体(即不仅仅是原型),它将被优化出来。

但是,您使用 getter 和 setter 是因为您可能希望获取或设置该变量以产生额外的副作用。就像改变物体的位置一样,也会改变附近物体在物理模拟等中的位置。

最后,在优化代码的上下文中,getter 和 setter 操作的开销非常小,除非代码很热,否则不值得担心。如果它很热,只需将 getter 或 setter 移动到头文件并内联它就很容易了。

因此,总而言之,getter 和 setter 非常值得少量或不存在的开销,因为它允许您非常具体地指定您的对象可以和不可以发生什么,它还允许您编组任何更改。

【讨论】:

  • +1 用于内联(尽管其余的也都在现场)。内联并忘记。
  • 但请务必记住,内联函数是 a) 只是一个建议,b) 只有在源文件包含所有可用信息时才有效,因此它必须在标题中.
  • 关于“微不足道”和“微不足道”的 cmets:函数调用会花费周期,而在科学计算中(大量的获取/设置发生在大型、长时间运行的循环中),它们可能会花费如果不进行优化,您将花费大量(墙壁)时间。也就是说,内联 getter/setter 通常是未来代码灵活性的好主意。
  • @TonyK。我同意它可能是需要的,但通常不是。好点虽然它可以加起来。始终使用分析来确定代码中的热点。并根据需要进行优化。
  • @OmnipotentEntity:在最近的编译器上,内联可以在链接时完成,这意味着即使函数的定义在实现文件中而不是在头文件中,也可以内联。 编辑:哦等等,我刚刚看到你是答案的作者!由于您在答案中唤起了链接时优化,因此我不理解您关于仅当定义位于标题中时才可能进行内联的评论。
【解决方案2】:

我对此的看法与之前的答案不同。

Getter 和 setter 表明你的类没有以有用的方式设计:如果你不从内部实现中抽象出外部行为,那么首先使用抽象接口是没有意义的,你可能以及使用普通的旧结构。

想想你真正需要什么操作。这几乎可以肯定不是直接访问位置和动量的 x-y-和 z-坐标,您宁愿将它们视为向量(至少在大多数计算中,这与优化)。所以你想实现一个基于向量的接口*,其中基本操作是向量加法、缩放和内积。不是按组件访问;您可能有时也需要这样做,但这可以通过单个 std::array<double,3> to_posarray() 成员或类似的东西来完成。

当内部组件xy ... vz 无法从外部访问时,您可以安全地更改内部实现,而无需中断模块外部的任何代码。这几乎就是 getter/setter 的重点;但是,当使用这些时,您只能做很多优化:任何真正的实现更改都不可避免地会使 getter 慢得多。
另一方面,您可以通过 SIMD 操作、外部库调用(可能在 CUDA 等加速硬件上)等优化基于矢量的接口。像to_posarray 这样的“batch-getter”仍然可以相当有效地实现,而单变量设置器则不能。


*这里是mathematical sense中的向量,不像std::vector

【讨论】:

    【解决方案3】:

    Getter 和 setter 可以让您的代码在未来更轻松地发展,如果 get 和 set 被证明是稍微复杂一点的任务的话。大多数 C++ 编译器都足够聪明,可以inline 那些简单的方法并消除函数调用的开销。

    【讨论】:

      【解决方案4】:

      这个问题可能有多种答案,但我把我的想法放在这里。

      在性能方面,对于简单的 POD 类型,成本几乎可以忽略不计。 但是还是有成本的,这取决于你返回的类型。对于粒子,不可能有太多数据。如果这是一个图像类(如 OpenCV cv::Mat)或 3d 数据(如 VTK 中的 PolyData),setter/getter 处理指针/迭代器比处理实际数据更好,以避免内存分配问题。

      当您想对事物进行模板化时,setter/getter 对于避免不明确的类型转换非常有用。 setter/getter 可以是访问私有/受保护成员的一种方式,这也允许您避免使用 x 作为变量的通用名称。此外,setter/getter 可以返回一个左值引用,它允许你做particle.getX() = 10.0 ;

      【讨论】:

      • particle.getX() = 10.0 ; - 但是在哪里/何时需要它?
      • @SChepurin 当您不仅想打破封装,还想可怕地打破它?
      • @Michael Kjörling,我认为这样更自然,为什么你说它破坏了封装?
      • 如果直接暴露一个成员变量违反了封装(通常和合理地争论),那么有一个函数如何返回对该变量的引用而不破坏封装?在这种情况下,我们甚至不是在谈论一个潜在的复杂类,而是一个原始值类型(保留地编写它,我不知道 C++ 中的确切术语是什么)。我绝对不会指望getX() 返回对内部成员变量的引用,这肯定不会减少混淆。
      • 但这是 C++ ...,数百万个粒子。如果这门课有安全问题,我同意你的看法。
      【解决方案5】:

      在这种情况下,您的计算的功能含义可能是:

      void Particle::updatePosition() { x += vx; y += vy; }

      或:

      void Particle::updatePositionX() { x += vx; }

      然后:

      粒子.updatePositionX();

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 1970-01-01
      • 2016-10-12
      • 2018-04-05
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 2019-11-26
      相关资源
      最近更新 更多