【问题标题】:Does defining a fluent interface have a performance impact?定义一个流畅的接口是否会对性能产生影响?
【发布时间】:2011-02-04 15:55:31
【问题描述】:

我刚刚阅读了this question,这又给我提出了另一个问题:

考虑这个类:

class Foo
{
public:
  void setA(int a) { m_a = a; }
  void setB(int b) { m_b = b; }
private:
  int m_a, m_b;
};

也可以使用“流利的接口”方法编写:

class Foo
{
public:
  Foo& setA(int a) { m_a = a; return *this; }
  Foo& setB(int b) { m_b = b; return *this; }
private:
  int m_a, m_b;
};

现在,如果我编写以下代码 sn-p:

int main()
{
  Foo foo;
  foo.setA(1);
  foo.setB(2);
}

如果我使用该类的第二个实现,额外的 return 指令是否会导致性能差异?

我应该打扰吗? (我的猜测是“不”)

【问题讨论】:

    标签: c++ fluent-interface


    【解决方案1】:

    如果我使用该类的第二个实现,额外的返回指令是否会导致性能差异?

    我不知道,你的编译器和优化器设置有吗?在您给出的确切情况下,我没有看到任何可以阻止任何开销被优化的东西,但我可以想象为一个没有优化这种情况的深奥平台编写一个幼稚的、次优的编译器。

    如果您认为在特定情况下这很重要,test it instead of assuming

    【讨论】:

      【解决方案2】:

      由于方法是内联的,编译器应该能够看到返回值未被使用并可能优化它。

      使用对您的项目设计最有意义的方式。然后,衡量性能,只有当它不够好时才会考虑优化代码。

      【讨论】:

        【解决方案3】:

        我认为由于编译器优化不会有任何区别。

        【讨论】:

          【解决方案4】:

          如果使用第2个实现,并且不需要set函数的返回值,那么写成可能会更好

            (void) foo.setA(1);
            (void) foo.setB(2);
          

          这样编译器或静态分析器就不会抱怨没有使用返回值。

          至于性能,返回引用可能(我不确定)与第一个实现相比会生成一/两条额外的汇编指令,但可能没有任何“真正的”差异。

          【讨论】:

            【解决方案5】:

            根据您定义类的方式,您不会发现两者之间有太大差异(如果有的话)。但是,如果您稍微修改一下您的设计,您将:

            class Foo1
            {
            public:
                Foo1(int a, int b) : m_a(a), m_b(b) {}
                void setA(int a) { m_a = a; }
                void setB(int b) { m_b = b; }
            private:
                int m_a, m_b;
            };
            
            class Foo2
            {
            public:
                Foo& setA(int a) { m_a = a;  return *this; }
                Foo& setB(int b) { m_b = b;  return *this; }
            private:
                int m_a, m_b;
            };
            

            初始化Foo1:

            Foo1 f(1, 2); // only constructor called
            

            会比初始化Foo2效率高得多:

            Foo2 b; // constructor called
            b.setA(1).setB(2); // 2 functions called
            

            在某些情况下,这不是问题。

            您对 Fluent 接口的另一个担忧是最终用户可能会错误地使用它们。在设计界面时,您希望将其设计为界面的用户很难破坏它。通过从每个 setter 中返回一个引用,如果用户代码存储了该引用,然后对象被移动或释放,那么您就有了一个悬空引用(甚至可能没有意识到)。

            【讨论】:

            • 效率更高?我的编译器为这两种情况生成完全相同的代码。特别要注意 Foo2 的构造函数是微不足道的。
            • 我们说的是 CPU 术语。单个构造函数调用
            • 并非总是如此。以It does not in this case 为例。
            • @Fred:您显然错过了我提到的对一个示例进行基准测试的编辑,因为这毫无意义。
            • 不,我没有,但感谢对我的回答的反对,这确实说明了这一点。如果真的没有意义,你为什么要在这里尝试?
            【解决方案6】:

            这些性能差异从来都不重要。但是,用实际应用程序的一些测量证明我错了。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-02-03
              • 1970-01-01
              • 1970-01-01
              • 2014-10-16
              • 2010-11-27
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多