I'm digging in glm library, and found this type of code, also there are some other simmilar stuff. My question is: what is a purpose to copy function parameter to const local variable inside function, like this -- T const a(angle). Is it for some performance benefits?
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER qua<T, Q> angleAxis(T const& angle, vec<3, T, Q> const& v)
{
T const a(angle);
T const s = glm::sin(a * static_cast<T>(0.5));
return qua<T, Q>(glm::cos(a * static_cast<T>(0.5)), v * s);
}
There’s no purpose.
This was probably done in a misguided attempt to avoid the indirection of repeatedly accessing angle (which, being a reference, is probably implemented by the compiler as a pointer). Whether this outweighs the cost of a copy is not obvious: if the type T is small and trivially copyable then making a copy is free but for larger types this will in fact incur a nontrivial overhead. On the other hand, the repeated pointer access can often be avoided entirely by the compiler.
Regardless of these considerations, if that optimisation was the purpose, it would have been more appropriate to pass angle by value instead: first passing by reference and then copying locally truly serves no purpose.
Related
I want to overload the == operator for a simple struct
struct MyStruct {
public:
int a;
float b;
bool operator==( ) { }
}
All the examples I'm seeing seem to pass the value by reference using a &.
But I really want to pass these structs by value.
Is there anything wrong with me writing this as
bool operator== (MyStruct another) { return ( (a==another.a) && (b==another.b) ); }
It should really not matter expect that you pay the penalty of a copy when you pass by value. This applies if the struct is really heavy. In the simple example you quote, there may not be a big difference.
That being said, passing by const reference makes more sense since it expresses the intent of the overloaded function == clearly. const makes sure that the overloaded function accidentally doesn't modify the object and passing by reference saves you from making a copy. For == operator, there is no need to pass a copy just for comparison purposes.
If you are concerned about consistency, it's better to switch the other pass by value instances to pass by const ref.
While being consistent is laudable goal, one shouldn't overdo it. A program containing only 'A' characters would be very consistent, but hardly useful. Argument passing mechanism is not something you do out of consistency, it is a technical decision based on certain technical aspects.
For example, in your case, passing by value could potentially lead to better performance, since the struct is small enough and on AMD64 ABI (the one which is used on any 64bit Intel/AMD chip) it will be passed in a register, thus saving time normally associated with dereferencing.
On the hand, in your case, it is reasonable to assume that the function will be inlined, and passing scheme will not matter at all (since it won't be passed). This is proven by codegen here (no call to operator== exist in generated assembly): https://gcc.godbolt.org/z/G7oEgE
I want to use matrix free sparse solvers with custom matrix-vector product object. Here is great example how to to it - https://eigen.tuxfamily.org/dox/group__MatrixfreeSolverExample.html
But in this example custom matrix-product object should be constant due to generic_product_impl signature
template<typename Dest>
static void scaleAndAddTo(
Dest& dst,
const MatrixReplacement& lhs,
const Rhs& rhs,
const Scalar& alpha)
In many my problems i need a lot of temporary buffers for each product call. It's pretty wise to allocate them once but i can't store them inside MatrixReplacement because it passed as const.
Is it possible in Eigen to overcome this problem?
There are two immediate options:
Use the mutable keyword for the members that need to change in const methods (i.e. your temporary buffers). This keyword makes sense where observable behavior of your class is const, despite you needing to modify members. Examples include cached values, mutexes, or your buffers.
C++ is not perfectly strict with propagating const. A const unique_ptr<T> will return a (non-const) T& when dereferenced (because the const says "you can't change the pointer", not "you can't change the pointee"; this is the same with builtin pointers). You can similarly wrap your "real" sparse matrix class in something that pretends to be const but allows non-const access to the matrix if the STL smart pointers are insufficient. If you give it an appropriate name then it's not as terrible as it sounds.
I recommend option 1.
All kinds of classes in the C++ standard library have a member swap function, including some polymorphic classes like std::basic_ios<CharT>. The template class std::shared_future<T> clearly is a value type and std::future<T> is a move-only value type. Is there any particular reason, they don't provide a swap() member function?
Member swap was a massive performance increase prior to std::move support in C++11. It was the way you could move one vector to another spot, for example. It was used in vector resizes as well, and it meant that inserting into a vector of vectors was not complete performance suicide.
After std::move arrived in C++11, with many sometimes-empty types the default implementation of std::swap:
template<class T>
void swap( T& lhs, T& rhs ) {
auto tmp = std::move(rhs);
rhs = std::move(lhs);
lhs = std::move(tmp);
}
is going to be basically as fast as a custom-written one.
Existing types with swap members are unlikely to lose them (at least immediately). Extending the API of a new type should, however, be justified.
If std::future is basically a wrapper around a std::unique_ptr< future_impl >, then the above is going to require 4 pointer reads, 3 pointer writes, and one branch. And an optimizating compiler who inlined it1 could reduce it down to 2 pointer reads and 2 pointer writes (using SSA2 for example), which is what an optimized .swap member function could do.
1 So it knows intermediate access to the lhs and rhs never occurs, thus the existence of tmp can be eliminated as-if once it proves tmp is empty and hence has a no-op dtor.
2 Static single assignment, where you break a program down such that every assignment to a primitive creates a brand new variable (with metadata). You then prove properties about that variable, and eliminate redundant ones.
Since const reference is pretty much the same as passing by value but without creating a copy (to my understanding). So is there a case where it is needed to create a copy of the variables (so we would need to use pass by value).
There are situations where you don't modify the input, but you still need an internal copy of the input, and then you may as well take the arguments by value. For example, suppose you have a function that returns a sorted copy of a vector:
template <typename V> V sorted_copy_1(V const & v)
{
V v_copy = v;
std::sort(v_copy.begin(), v_copy.end());
return v;
}
This is fine, but if the user has a vector that they never need for any other purpose, then you have to make a mandatory copy here that may be unnecessary. So just take the argument by value:
template <typename V> V sorted_copy_2(V v)
{
std::sort(v.begin(), v.end());
return v;
}
Now the entire process of producing, sorting and returning a vector can be done essentially "in-place".
Less expensive examples are algorithms which consume counters or iterators which need to be modified in the process of the algorithm. Again, taking those by value allows you to use the function parameter directly, rather than requiring a local copy.
It's usually faster to pass basic data types such as ints, floats and pointers by value.
Your function may want to modify the parameter locally, without altering the state of the variable passed in.
C++11 introduces move semantics. To move an object into a function parameter, its type cannot be const reference.
Like so many things, it's a balance.
We pass by const reference to avoid making a copy of the object.
When you pass a const reference, you pass a pointer (references are pointers with extra sugar to make them taste less bitter). And assuming the object is trivial to copy, of course.
To access a reference, the compiler will have to dereference the pointer to get to the content [assuming it can't be inlined and the compiler optimises away the dereference, but in that case, it will also optimise away the extra copy, so there's no loss from passing by value either].
So, if your copy is "cheaper" than the sum of dereferencing and passing the pointer, then you "win" when you pass by value.
And of course, if you are going to make a copy ANYWAY, then you may just as well make the copy when constructing the argument, rather than copying explicitly later.
The best example is probably the Copy and Swap idiom:
C& operator=(C other)
{
swap(*this, other);
return *this;
}
Taking other by value instead of by const reference makes it much easier to write a correct assignment operator that avoids code duplication and provides a strong exception guarantee!
Also passing iterators and pointers is done by value since it makes those algorithms much more reasonable to code, since they can modify their parameters locally. Otherwise something like std::partition would have to immediately copy its input anyway, which is both inefficient and looks silly. And we all know that avoiding silly-looking code is the number one priority:
template<class BidirIt, class UnaryPredicate>
BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p)
{
while (1) {
while ((first != last) && p(*first)) {
++first;
}
if (first == last--) break;
while ((first != last) && !p(*last)) {
--last;
}
if (first == last) break;
std::iter_swap(first++, last);
}
return first;
}
A const& cannot be changed without a const_cast through the reference, but it can be changed. At any point where code leaves the "analysis range" of your compiler (maybe a function call to a different compilation unit, or through a function pointer it cannot determine the value of at compilation time) it must assume that the value referred to may have changed.
This costs optimization. And it can make it harder to reason about possible bugs or quirks in your code: a reference is non-local state, and functions that operate only on local state and produce no side effects are really easy to reason about. Making your code easy to reason about is a large boon: more time is spent maintaining and fixing code than writing it, and effort spent on performance is fungible (you can spent it where it matters, instead of wasting time on micro optimizations everywhere).
On the other hand, a value requires that the value be copied into local automatic storage, which has costs.
But if your object is cheap to copy, and you don't want the above effect to occur, always take by value as it makes the compilers job of understanding the function easier.
Naturally only when the value is cheap to copy. If expensive to copy, or even if the copy cost is unknown, that cost should be enough to take by const&.
The short version of the above: taking by value makes it easier for you and the compiler to reason about the state of the parameter.
There is another reason. If your object is cheap to move, and you are going to store a local copy anyhow, taking by value opens up efficiencies. If you take a std::string by const&, then make a local copy, one std::string may be created in order to pass thes parameter, and another created for the local copy.
If you took the std::string by value, only one copy will be created (and possibly moved).
For a concrete example:
std::string some_external_state;
void foo( std::string const& str ) {
some_external_state = str;
}
void bar( std::string str ) {
some_external_state = std::move(str);
}
then we can compare:
int main() {
foo("Hello world!");
bar("Goodbye cruel world.");
}
the call to foo creates a std::string containing "Hello world!". It is then copied again into the some_external_state. 2 copies are made, 1 string discarded.
The call to bar directly creates the std::string parameter. Its state is then moved into some_external_state. 1 copy created, 1 move, 1 (empty) string discarded.
There are also certain exception safety improvements caused by this technique, as any allocation happens outside of bar, while foo could throw a resource exhausted exception.
This only applies when perfect forwarding would be annoying or fail, when moving is known to be cheap, when copying could be expensive, and when you know you are almost certainly going to make a local copy of the parameter.
Finally, there are some small types (like int) which the non-optimized ABI for direct copies is faster than the non-optimized ABI for const& parameters. This mainly matters when coding interfaces that cannot or will not be optimized, and is usually a micro optimization.
I have a class like
struct S {
bool foo(const AType& v) const {
return values.count(&v); // compile error due to the constness of v
}
private:
std::set<AType*> values;
};
This is a simplified version. In real code, foo does some complex things.
The code produces an error
invalid conversion from ‘const AType*’ to ‘std::set<AType*>::key_type {aka AType*}’
I think foo should take 'const AType& v' because it does not mutate v.
The type of the member variable 'values' can not be std::set<const AType*> because some methods of the struct S call non-const methods of the elements contained in 'values'.
I can cast constness of 'v' away:
bool foo(const AType& v) const {
return values.count((AType*) &v);
}
But I think this may not be a good solution in general.
What solution could I have?
template<class T>
struct const_ptr_compare:std::less<T const*> {
typedef void is_transparent;
};
std::set<AType*, const_ptr_compare<AType>> values;
and bob is your uncle.
I defined a comparator that can transparently handle T const* comparisons as well as T* comparisons. I then told std::set that it is transparent.
The is_transparent technique is a C++14 enhancement to std::set. Your compiler may already have support for it.
If you want to be able to pass in base-classes-of-T a bit more work needs to be done. You need a function object that tests its two arguments (each pointers to const) to see which is a base class of the other, and does a std::less<base const*>{}(lhs, rhs) using that base class. However, that is going further down the rabbit hole than we need to.
A C++11/03 approach could involve making the editable portions of AType mutable, and having a const AType* set. Failing that, a const_cast<AType*> is reasonable.
Please don't use a C-style cast: they are almost never required, and they can be accidentally too powerful.
The root of the problem is this:
The type of the member variable 'values' can not be std::set because some methods of the struct S call non-const methods of
the elements contained in 'values'.
You are not supposed to mutate the set key in any way.
You should be using a map, where the actual key parts are in the key and are const, and the mutating parts are in the value and are non-const.
If this is impractical for your design, I understand. The const_cast workaround will solve the issue. It feels inelegant, but that's because your usage of set is inelegant.
This is just one of the many problems of the const correctness concept: it doesn't scale by composition.
The casting solution is just ok, if you feel it's "dirty" in some way probably you're overestimating cleanness of the const concept.
Consider that defining special types for const_iterator and const_reverse_iterator was needed or that sometimes const correctness requires actual code duplication (e.g. in many cases for operator[]) or that if you've an object containing a non-const pointer you can mutate the pointed-to object freely and even delete it in const members.
Your cast doesn't look that bad in comparison :-)