Let's imagine we have a struct for holding 3 doubles with some member functions:
struct Vector {
double x, y, z;
// ...
Vector &negate() {
x = -x; y = -y; z = -z;
return *this;
}
Vector &normalize() {
double s = 1./sqrt(x*x+y*y+z*z);
x *= s; y *= s; z *= s;
return *this;
}
// ...
};
This is a little contrived for simplicity, but I'm sure you agree that similar code is out there. The methods allow you to conveniently chain, for example:
Vector v = ...;
v.normalize().negate();
Or even:
Vector v = Vector{1., 2., 3.}.normalize().negate();
Now if we provided begin() and end() functions, we could use our Vector in a new-style for loop, say to loop over the 3 coordinates x, y, and z (you can no doubt construct more "useful" examples by replacing Vector with e.g. String):
Vector v = ...;
for (double x : v) { ... }
We can even do:
Vector v = ...;
for (double x : v.normalize().negate()) { ... }
and also:
for (double x : Vector{1., 2., 3.}) { ... }
However, the following (it seems to me) is broken:
for (double x : Vector{1., 2., 3.}.normalize()) { ... }
While it seems like a logical combination of the previous two usages, I think this last usage creates a dangling reference while the previous two are completely fine.
Is this correct and Widely appreciated?
Which part of the above is the "bad" part, that should be avoided?
Would the language be improved by changing the definition of the range-based for loop such that temporaries constructed in the for-expression exist for the duration of the loop?
Is this correct and Widely appreciated?
Yes, your understanding of things is correct.
Which part of the above is the "bad" part, that should be avoided?
The bad part is taking an l-value reference to a temporary returned from a function, and binding it to an r-value reference. It is just as bad as this:
auto &&t = Vector{1., 2., 3.}.normalize();
The temporary Vector{1., 2., 3.}'s lifetime cannot be extended because the compiler has no idea that the return value from normalize references it.
Would the language be improved by changing the definition of the range-based for loop such that temporaries constructed in the for-expression exist for the duration of the loop?
That would be highly inconsistent with how C++ works.
Would it prevent certain gotchas made by people using chained expressions on temporaries or various lazy-evaluation methods for expressions? Yes. But it would also be require special-case compiler code, as well as be confusing as to why it doesn't work with other expression constructs.
A much more reasonable solution would be some way to inform the compiler that the return value of a function is always a reference to this, and therefore if the return value is bound to a temporary-extending construct, then it would extend the correct temporary. That's a language-level solution though.
Presently (if the compiler supports it), you can make it so that normalize cannot be called on a temporary:
struct Vector {
double x, y, z;
// ...
Vector &normalize() & {
double s = 1./sqrt(x*x+y*y+z*z);
x *= s; y *= s; z *= s;
return *this;
}
Vector &normalize() && = delete;
};
This will cause Vector{1., 2., 3.}.normalize() to give a compile error, while v.normalize() will work fine. Obviously you won't be able to do correct things like this:
Vector t = Vector{1., 2., 3.}.normalize();
But you also won't be able to do incorrect things.
Alternatively, as suggested in the comments, you can make the rvalue reference version return a value rather than a reference:
struct Vector {
double x, y, z;
// ...
Vector &normalize() & {
double s = 1./sqrt(x*x+y*y+z*z);
x *= s; y *= s; z *= s;
return *this;
}
Vector normalize() && {
Vector ret = *this;
ret.normalize();
return ret;
}
};
If Vector was a type with actual resources to move, you could use Vector ret = std::move(*this); instead. Named return value optimization makes this reasonably optimal in terms of performance.
for (double x : Vector{1., 2., 3.}.normalize()) { ... }
That is not a limitation of the language, but a problem with your code. The expression Vector{1., 2., 3.} creates a temporary, but the normalize function returns an lvalue-reference. Because the expression is an lvalue, the compiler assumes that the object will be alive, but because it is a reference to a temporary, the object dies after the full expression is evaluated, so you are left with a dangling reference.
Now, if you change your design to return a new object by value rather than a reference to the current object, then there would be no issue and the code would work as expected.
IMHO, the second example is already flawed. That the modifying operators return *this is convenient in the way you mentioned: it allows chaining of modifiers. It can be used for simply handing on the result of the modification, but doing this is error-prone because it can easily be overlooked. If I see something like
Vector v{1., 2., 3.};
auto foo = somefunction1(v, 17);
auto bar = somefunction2(true, v, 2, foo);
auto baz = somefunction3(bar.quun(v), 93.2, v.qwarv(foo));
I wouldn't automatically suspect that the functions modify v as a side-effect. Of course, they could, but it would be confusing. So if I was to write something like this, I would make sure that v stays constant. For your example, I would add free functions
auto normalized(Vector v) -> Vector {return v.normalize();}
auto negated(Vector v) -> Vector {return v.negate();}
and then write the loops
for( double x : negated(normalized(v)) ) { ... }
and
for( double x : normalized(Vector{1., 2., 3}) ) { ... }
That is IMO better readable, and it's safer. Of course, it requires an extra copy, however for heap-allocated data this could likely be done in a cheap C++11 move operation.
Related
I have a class Foo that stores Eigen MatrixXd and VectorXd of matching dimensions and offers a simple function .mult() that performs matrix-vector multiplication. And I have a function that calls mult(), takes a segment of the returned vector, and does some further computation. Here is a simplified version of the code:
#include <Eigen/Dense>
class Foo {
Eigen::MatrixXd X;
Eigen::VectorXd v;
public:
Foo() {
X.resize(2, 2);
v.resize(2);
X << 1, 4, 2, 4;
v << -1, 1;
}
Eigen::VectorXd mult() {
return X * v;
}
};
Eigen::VectorXd bar() {
Foo f;
Eigen::VectorXd val = f.mult().segment(1, 1);
// Use val to do some computation.
Eigen::VectorXd ret = val.array() + 2;
return ret;
}
During a code review, a comment was raised that this could lead to dangling reference of the unnamed/temp variable that stores the result of f.mult(). And a general question was raised regarding the lifetime of temporary variables that aren't assigned a name.
If I understand RVO correctly, a temporary object will be created on the stack whose address will be passed to f.mult(), which will then store the result of X * v to the passed in memory address. And this temporary object will go out of scope when bar() terminates. There shouldn't be any dangling reference or concerns regarding the scope of the temporary and unassigned variable. But I'm not so sure.
Eigen is an elegant but a complex library and I hope to ensure that I'm using it in safely as possible. Thanks in advance!
What you are doing is save (but inefficient).
f.mult() returns a Eigen::VectorXd object by value which exist for the rest of the statement ("until the next ;"). So calling segment() on it is safe, as long as you store that result into a VectorXd (and not into an auto object).
To get a segment of a matrix-vector product it would however be more efficient to just multipy the corresponding sub-block of the matrix, i.e.:
(X*v).segment(a,b) == X.rows(a,b) * v
The following function is supposed to take the coefficients of a polynomial and create a function of time from them:
std::function<double(double)> to_equation(const std::vector<double>& coefficients)
{
return [coefficients](double t)
{
auto total = 0.0;
for (int i = 0; i < coefficients.size(); i++)
{
total += coefficients[i] * pow(t,i);
return total;
}
};
}
It should be usable as follows:
std::vector<double> coefficients = {1.0,2.0,3.0};
auto f = to_equation(coefficients);
auto value = f(t);
The code does however not work as intended, since at the time of execution of f(t), not the coefficients passed to to_equation(coefficients) are used, but some totally different values magically captured from the context. What is happening and how can I fix that?
Well, you are returning a lambda that capture coefficients by value. If you pass some vector to the to_equation function, all values will be copied, and the lambda won't refer to the original vector anymore.
I suggest this solution:
// auto is faster than std::function
auto to_equation(const std::vector<double>& coefficients)
{
// Here, you capture by reference.
// The lambda will use the vector passed in coefficients
return [&coefficients](double t)
{
// ...
};
}
However, you must sometime deal with code like this:
std::function<double(double)> f;
{
std::vector<double> coeff{0.2, 0.4, 9.8};
f = to_equation(coeff);
}
auto result = f(3);
This is bad, the vector coeff don't live long enough, and we refer to it after the vector is destroyed.
I suggest adding this overload to your function:
// when a vector is moved into coefficients, move it to the lambda
auto to_equation(std::vector<double>&& coefficients)
{
// Here, you capture by value.
// The lambda will use it's own copy.
return [coeff = std::move(coefficients)](double t)
{
// ...
};
}
Then, calling your function is possible in both ways:
std::vector<double> coeff{0.2, 0.4, 9.8};
auto f1 = to_equation(coeff); // uses reference to coeff
auto f2 = to_equation({0.2, 0.4, 9.8}) // uses value moved into the lambda
You can capture by reference, instead of by value. But, of course, if the underlying vector goes out of scope and gets destroyed before the lambda gets invoked, you'll have a big mess on your hands.
The safest course of action is to use a std::shared_ptr<std::vector<double>> instead of a plain vector, and capture that by value. Then, the lambda will always, essentially, feed on whatever were the most recent set of coefficients, and won't blow up if it gets called after all other references to the underlying vector, from whatever code computed them, go out of scope.
(Of course, you have to keep in mind what's going to happen here if the lambda gets copied around, since all copies of the original lambda will be using the same vector).
For more information, open the chapter of your C++ book that explains the difference between capturing by value and by reference, when using lambdas.
So I want to make an executable with three functions:
This would be an example:
float vec(int opt, int t)
{
int i;
float * v = new float[t];
// Do stuff with v
return * v;
}
}
It gets arguments opt and t from main. Then main needs to get v back to use it in another function.
What is the best way to do this?
The return type of vec should be float *, and your return statement should be return v. Dereferencing v with * just gives you the first element of the array.
I'll note that this kind of design is bad style. It relies on the caller to free the dynamically allocated array. It would be better to have the caller create an array and pass it by reference to vec, or have vec return a different container statically. #Mat suggested std::vector; that's probably a good choice.
You also have an extra } at the end of your function. Get rid of it.
Well, your signature says that the function returns a single float, not an array of floats. To answer your question directly...
float *vec(int t)
{
float * v = new float[t];
// Do stuff with v
return v;
}
What is the best way to do this?
Well that's a different question entirely. The "best" way would be to return a std::vector<float> and avoid manual memory management altogether.
Lets say I have the following:
struct point
{
double x;
double y;
double z;
};
I can write the following:
void point_mult(point& p, double c) { p.x *= c; p.y *= c; p.z *= c; }
void point_add(point& p, const point& p2) { p.x += p2.x; p.y += p2.y; p.z += p2.z; }
So I can then do the following:
point p{1,2,3};
point_mult(p, 2);
point_add(p, point{4,5,6});
This requires no copies of point, and only two constructions, namely the construction of point{1,2,3} and the construction of point{4,5,6}. I believe this applies even if point_add, point_mult and point{...} are in separate compilation units (i.e. can't be inlined).
However, I'd like to write code in a more functional style like this:
point p = point_add(point_mult(point{1,2,3}, 2), point{4,5,6});
How can I write point_mult and point_add such that no copies are required (even if point_mult and point_add are in separate compilation units), or is functional style forced to be not as efficient in C++?
Let's ignore the implicit fallacy of the question (namely that copying automatically means reduced efficiency). And let's also ignore the question of whether any copying would actually happen, or whether it would all be elided away by any half-decent compiler. Let's just take it on face value: can this be done without copying?
Yes, and it is probably the only other legitimate use for r-value references (though the previously ignored stipulations make this use case dubious):
point &&point_mult(point &&p, double c);
Of course, this will only bind to temporaries. So you would need an alternate version for l-values:
point &point_mult(point &p, double c);
The point is that you pass the references through as they are, either as references to temporaries or references to l-values.
It can be done with really ugly template metaprogramming. For example eigen uses templates so that expressions like matrix1 + matrix2 * matrix3 don't need to create any temporaries. The gist of how it works is the + and * operators for matrices don't return Matrix objects but instead return some kind of matrix expression object which is templatized on the types of the expression paramaters. This matrix expression object can then compute parts of the expression only when they are needed instead of creating temporary objects to store the result of subexpressions.
Actually implementing this can get quite messy. Have a look at Eigen's source if your interested. Boost's uBlas also does something similar, though it's not as extensively as eigen.
An efficient (and generalized) technique is expression templates. You can read a nice introductory explanation here.
It's difficult to implement and being based on templates, you cannot use separate compilation units, but it's very efficient. An interesting application in symbolic computation is parsing: Boost.Spirit builds very efficient parsers out of them.
C++11 auto keywords helps usage on practical programming tasks, as always when dealing with complex types, see this other answer.
First, why not use "better" functions ?
struct Point {
double x;
double y;
double z;
Point& operator+=(Point const& right) {
x += right.x; y += right.y; z += right.z;
return *this;
}
Point& operator*=(double f) {
x *= f; y *= f; z *= f;
return *this;
}
};
Now it can be used as:
Point p = ((Point{1,2,3} *= 2) += Point{4,5,6});
But I truly think that you worry too much about copies here (and performance).
Make it work
Make it fast
If you don't have anything that already works, talking about performance is akin to chasing mills... bottlenecks are rarely where we thought they would be.
Change the definition of point_mult() to:
point& point_mult(point& p, double c) { p.x *= c; p.y *= c; p.z *= c; return p; }
^^^^^^ ^^^^^^^^^
And call it as:
point & p = point_add(point_mult(*new point{1,2,3}, 2), point{4,5,6});
^^^ ^^^^^
there is no copy involved. However, you have to later do delete &p; for releasing the memory.
I recently hit a problem and the only way I can see to avoid it is to use const_cast - but I'm guessing there is a way I'm not thinking of to avoid this without otherwise changing the function of the code. The code snippet below distills my problem into a very simple example.
struct Nu
{
Nu() {v = rand();}
int v;
};
struct G
{
~G()
{
for(auto it = _m.begin(); it != _m.end(); it++) delete it->first;
}
void AddNewNu()
{
_m[new Nu] = 0.5f;
}
void ModifyAllNu()
{
for(auto it = _m.begin(); it != _m.end(); it++) it->first->v++;
}
float F(const Nu *n) const
{
auto it = _m.find(n);
// maybe do other stuff with it
return it->second;
}
map<Nu*, float> _m;
};
Here, suppose Nu is actually a very large struct whose layout is already fixed by the need to match an external library (and thus the "float" can't simply be folded into Nu, and for various other reasons it can't be map<Nu, float>). The G struct has a map that it uses to hold all the Nu's it creates (and ultimately to delete them all on destruction). As written, the function F will not compile - it cannot cast (const Nu *n) to (Nu n) as expected by std::map. However, the map can't be switched to map<const Nu*, float> because some non-const functions still need to modify the Nu's inside _m. Of course, I could alternatively store all these Nu's in an additional std::vector and then switch the map type to be const - but this introduces a vector that should be entirely unnecessary. So the only alternative I've thought of at the moment is to use const_cast inside the F function (which should be a safe const_cast) and I'm wondering if this is avoidable.
After a bit more hunting this exact same problem has already been addressed here: Calling map::find with a const argument
This is because the map expects Nu* const, but you have given it a const Nu*. I also find it highly illogical and don't understand why, but this is how it is.
"find" in your case will return a const_iterator. putting:
map<Nu*,float>::const_iterator it = _m.find(n);
...
return it->second;
should work I think.
Since you are in a const method you can only read your map of course, not write/modify it