Reputation: 981
I am implementing some classes to represent mappings (in the mathematical sense), i.e., f : R x R^n -> R^n. I would like to implement an abstract base class that either: 1) Takes a std::array as a reference and modifies it or 2) returns a std::array (by value or by reference, not sure?)
The syntax of option 2 is more desirable to me simply because I think the code will look more like the math I'm trying to represent, but I want to make sure I am not needlessly copying things and inducing a bunch of undesired overhead. For example, if I had:
// Function f declaration
std::array<double, 4> f(double t, const std::array<double, 4> & x);
// Some code snippet that uses f
std::array<double, 4> x = {0.0, 1.0, 2.0, 3.0};
double t = 0.0;
std::array<double, 4> dxdt = f(t, x);
How can I determine whether a copy is being performed on the last line, or how can I ensure that it doesn't happen?
Within the definition of f(), what would I need to do (if anything) to ensure that this is returned without a call to the copy constructor? I want to keep the usage simple so clients don't need to use pointers or smart pointers, but maybe this is necessary?
I know I can change this to return void and just make one of the arguments be std::array dxdt, but I like the return value syntax better, as long as there is no performance penalties or memory leak issues.
Upvotes: 4
Views: 9479
Reputation: 8431
Don't worry: this is a very common use case, well understood by compilers. Make sure to enable optimizations though. One more thing, if your array is 4 double
long, you probably have more important things to optimize before this. Don't forget that optimizing before you know you need it (i.e. you measured) is evil.
Now, if you really want to make sure there is no copy, you can have a look at the assembly code (how depends on your compiler/tools).
Alternatively you could write a class of your own where you print something in the copy constructor and the assignment operator to make sure they are not called, but you won't be able to do that with std::array<>
unless you derive from it which is not allowed (it will compile and run though).
Upvotes: 2
Reputation: 20759
It should be something you shouldn't care, since optimizing copies is a compiler problem. But compilers are still Turing-based machines that cannot invent optimization themselves.
As far I know most of today's compilers behave, if a function:
The compiler allocates that variable on the stack in the place it has to be to be evaluated by the expression the function call belongs. No copy are generated for that.
If your function have multiple exits returning different expressions this -apart some particular cases- cannot be done.
So, in general, if you have to return some wide object, just declare it and make sure all the return statements return just it.
Upvotes: 9
Reputation: 2590
If you return by reference then there is no copy operation going on (really we're just dealing with 4 bytes, a memory address).
std::array<double, 4> f(double t, const std::array<double, 4> & x);
...can be turned into:
std::array<double, 4>& f(double t, const std::array<double, 4> & x);
...provided that the returned value is not a local stack-allocated variable within the function itself (because then it will be a dangling reference after being returned).
The compiler would probably do this automatically in some cases, but being explicit about it is better - as you say, you want to ensure no copying is occuring.
Upvotes: 0
Reputation: 11232
I believe you need not worry about unnecessary copying as compiler is pretty good at optimizing these things. It can use RVO (Return Value Optimization) to eliminate unnecessary copies. And if you have a C++11 supported compiler, copying is further reduced due to the move
semantics.
Upvotes: 1