2

I just read this question, which raises for me another question:

Consider this class:

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

Which could also be written using the "fluent interface" method:

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;
};

Now, if I write the following code snippet:

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

Is there a performance difference induced by the additional return directives if I use the second implementation of the class ?

Should I bother ? (My guess is "no")

Community
  • 1
  • 1
ereOn
  • 53,676
  • 39
  • 161
  • 238

6 Answers6

4

Is there a performance difference induced by the additional return directives if I use the second implementation of the class?

I don't know, is there with your compiler and optimizer settings? I see nothing that prevents any overhead from being optimized away in the exact case you give, but I can imagine writing a naive, sub-optimal compiler for an esoteric platform which did not optimize this case.

If you think it matters in a given situation, test it instead of assuming.

Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
0

I think there will be no difference due to compiler optimization.

vinnyspb
  • 46
  • 1
  • 2
0

If the 2nd implementation is used and the return value of the set functions are not required, then it may be better to write as

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

so that the compiler or static analyzer does not complain that the return value is not used.

As for performance, returning the reference may (I am not sure) generate one/two additional assembly instructions compared to the 1st implementation, but may not any "real" difference.

Arun
  • 19,750
  • 10
  • 51
  • 60
0

Since the methods are inlined, the compiler should be able to see that the return value is unused and possibly optimize it away.

Use whichever way makes the most sense for your project design. Then, measure the performance and only if it's not good enough would you consider optimizing the code.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

With the way you've defined the classes, you won't see much of a difference (if any) between the two. However, if you fix your design a bit, you will:

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;
};

Initializing Foo1:

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

will be far more efficient than initializing Foo2:

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

In some cases, that won't be a concern.

An additional concern you have with Fluent Interfaces is the ability for the end-user to use them incorrectly. When designing an interface, you want to design it so that it is very difficult for the user of your interface to break it. By returning a reference from every setter, if the user-code stored that reference and then the object is moved or deallocated, you have a dangling reference (and may not even realize it).

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • Far more efficient? My compiler generates the exact same code for both of these exact cases. In particular, note that Foo2's constructor is trivial. – Fred Nurk Feb 04 '11 at 16:10
  • We are speaking in CPU terms. A single constructor call < constructor + 2 function calls. Always. Meyers also has 2-3 items that discuss this (in dealing with constructor initialization) in "Effective C++". The principle remains the same here. EDIT: Also note that this is a very trivial example so benchmarking it would be meaningless. – Zac Howland Feb 04 '11 at 16:13
  • Not always. [It does not in this case](http://codepad.org/P9JhlUIl), for example. – Fred Nurk Feb 04 '11 at 16:29
  • @Fred: You apparently missed the edit where I mention that benchmarking an example as trivial as this is meaningless. – Zac Howland Feb 04 '11 at 16:35
  • No, I didn't, but thanks for the downvote on my answer which does make that exact point. If it is truly meaningless, why do you attempt to do it here? – Fred Nurk Feb 04 '11 at 16:41
  • @Fred: I don't attempt to do it. I simply show that you are taking a single operation and making it into 3 (and leaving the class declarations inlined for simplicity). – Zac Howland Feb 04 '11 at 16:51
  • You don't? I must've completely misinterpreted "will be far more efficient than". What is that saying, if it isn't comparing performance? – Fred Nurk Feb 04 '11 at 17:20
0

Those kinds of performance differences are never important. But, prove me wrong with some measurements of a real application.

Raedwald
  • 46,613
  • 43
  • 151
  • 237