1

Hello. I looked for an answer but did not found it for this specific question. Here I found an article which shows how the Visual C++ compiler eliminates redundant Copy constructor and Destructor calls in various situations. I believe the same is true for Clang and GCC.

There are two structs: input data Waveform and result Analyzed. And two functions do the same work but returns a result in different ways. 1st creates a local Analyzed and returns it (copy), 2nd takes reference to an already created object to fill it, returns the same.

struct Waveform;
struct Analyzed;

Analyzed  analyze( Waveform const& wf );  // Form 1
Analyzed& analyze( Waveform const& wf, Analyzed& an );  // Form 2

Example usage, assuming Waveform wf already in scope:

auto an0 = analyze(wf);
Analyzed const& an1 = analyze(wf);

Analyzed an3;
analyze(wf,an3);

As for me Form 1 is shorter and more convenient.

As far as I know, in C a good practice considered passing to function pointers to a prealloated memory (so user is responsible for memory) and not to return objects bigger than sizeof(int), but return pointer or error number.

The question. Is one of the analyze() forms better? Why?
Is there any performance issues, extra copies, pitfalls?
Any special cases?


I also can imagine how Form 1 reuses Form 2:

Analyzed  analyze( Waveform const& wf ){
  Analyzed an;
  analyze(wf,an);
  return an;
}

< spoiler > Longer description. There are two structs: Waveform represents a signal, and Analyzed - characteristics of the signal.

struct Waveform {
  size_t len;
  float *arr;
  float sampleRate;
  //...
}

struct Analyzed {
  struct Entry { size_t idx; float value; };
  Entry max;
  Entry min;
  float peakToPeak;
  float mean;
  //...
};

Analyzed  analyze( Waveform const& wf );
Analyzed& analyze( Waveform const& wf, Analyzed& an );
Community
  • 1
  • 1
kyb
  • 7,233
  • 5
  • 52
  • 105

1 Answers1

1

This form is preferred by many people now:

auto a = analyze(wf);

It's simple to write and simple to understand; nothing can go wrong. The C++17 draft specification includes guarantees that no intermediate temporary objects will be involved; C++14 made that optional. Most compilers did take up the option.

If you compare this with:

Analyzed an;
analyze(wf, an);

two of the major differences are:

  • It's not clear just from reading the code whether the function argument is an "in", "out", or "in-out" parameter. You'd have to look up the documentation.
  • This won't even work at all if Analyzed has no default-constructor. Which is not uncommon; it's following good object-oriented principles to have a constructor set an object up; as opposed to having the constructor make a dummy shell that will get "initialized" later.

Both of which make the code less easy to understand and more likely to have coding mistakes associated with them.

M.M
  • 138,810
  • 21
  • 208
  • 365