Optimising Iterator Definitions - c++

This is a (hopefully) really simple question - I have been told recently that using C++ style initialisation is better than traditional (and more common) assignment.
So this code:
std::SomeSTLContainer::const_iterator it = container.begin();
std::SomeSTLContainer::const_iterator itEnd = container.end();
would be 'slower' or less efficient than:
std::SomeSTLContainer::const_iterator it ( container.begin() );
std::SomeSTLContainer::const_iterator itEnd ( container.end() );
I understand the reason for this - the first example causes default construction and initialisation then subsequent assignment rather than specific construction and direct assignment in the second example. However, on modern processors / compilers, does it really make a difference?

I have been told recently that using C++ style initialisation is better than traditional (and more common) assignment.
This is simply wrong.
I understand the reason for this - the first example causes default construction and initialisation then subsequent assignment rather than specific construction and direct assignment in the second example. However, on modern processors / compilers, does it really make a difference?
No, it doesn't make a difference. The C++ standard explicitly allows the assignment in that case to be omitted so that the same code will be produced. In practice, all modern C++ compilers do this.
Additionally, Charles is right: this would never call the assignment operator but rather the copy constructor. But as I've said, even this doesn't happen.

Your reasoning is not quite correct. Using an '=' in the definition does not cause default construction and assignment. In the 'worst' case, it uses the copy constructor from a temporary generated from the right hand side of the '='.
If the type of the right hand side is (const/volatile aside) of the same type or a derived type of the object being initialized then the two forms of construction are equivalent.

No, typically. This is because iterators are coded to be very thin wrappers, and optimizers are quite aggressive when it comes to thin wrappers. E.g. the normal iterator method is just a simple pointer operation, and the function body is available from the header. This makes it trivially inlinable. In this case, an iterator copy is behind the scenes probably just a pointer copy, so the same holds.

This really depends on the case and the general rule of thumb should be applied: measure.
If there are a lots of instantiations of those iterators (maybe in nested and sort loops, those shorter constructors can easily make a difference).
Altough as you suggested, many compilers already can optimize those on their own.
To be really sure if your compiler does this there is just one way: measure

A a = A( arg1, arg2, ... );
This assignment can, as Rudolf stated, be replaced by a simple construction: it's a construction. And indeed, it would be compiled into the equivalent of the more succinct
A a( arg1, arg2, ...);
It's mostly a style issue, but I prefer not mixing the 'assigment-style' construction with 'initializer-style' construction. This way I induce consistency throughout my code. This boils down to: always use initializer style construction :).

Related

Where do standard library or compilers leverage noexcept move semantics (other than vector growth)?

Move operations should be noexcept; in the first place for intuitive and reasonable semantics. The second argument is runtime performance. From the Core Guidelines, C.66, "Make move operations noexcept":
A throwing move violates most people’s reasonably assumptions. A non-throwing move will be used more efficiently by standard-library and language facilities.
The canonical example for the performance-part of this guideline is the case when std::vector::push_back or friends need to grow the buffer. The standard requires a strong exception guarantee here, and this can only move-construct the elements into the new buffer if this is noexcept - otherwise, it must be copied. I get that, and the difference is visible in benchmarks.
However, apart from this, I have a hard time finding real-world evidence of the positive performance impact of noexcept move semantics. Skimming through the standard library (libcxx + grep), we see that std::move_if_noexcept exists, but it's almost not used within the library itself. Similarly, std::is_noexcept_swappable is merely used for fleshing out conditional noexcept qualifiers. This doesn't match existing claims, for example this one from "C++ High Performance" by Andrist and Sehr (2nd ed., p. 153):
All algorithms use std::swap() and std::move() when moving elements around, but only if the move constructor and move assignment are marked noexcept. Therefore, it is important to have these implemented for heavy objects when using algorithms. If they are not available and exception free, the elements will be copied instead.
To break my question into pieces:
Are there code paths in the standard library similar to the std::vector::push_back, that run faster when fed with std::is_nothrow_move_constructible types?
Am I correct to conclude that the cited paragraph from the book is not correct?
Is there an obvious example for when the compiler will reliably generate more runtime-efficient code when a type adheres to the noexcept guideline?
I know the third one might be a bit blurry. But if someone could come up with a simple example, this would be great.
Background: I refer to std::vector's use of noexcept as "the vector pessimization." I claim that the vector pessimization is the only reason anyone ever cared about putting a noexcept keyword into the language. Furthermore, the vector pessimization applies only to the element type's move constructor. I claim that marking your move-assignment or swap operations as noexcept has no "in-game effect"; leaving aside whether it might be philosophically satisfying or stylistically correct, you shouldn't expect it to have any effect on your code's performance.
Let's check a real library implementation and see how close I am to wrong. ;)
Vector reallocation. libc++'s headers use move_if_noexcept only inside __construct_{forward,backward}_with_exception_guarantees, which is used only inside vector reallocation.
Assignment operator for variant. Inside __assign_alt, the code tag-dispatches on is_nothrow_constructible_v<_Tp, _Arg> || !is_nothrow_move_constructible_v<_Tp>. When you do myvariant = arg;, the default "safe" approach is to construct a temporary _Tp from the given arg, and then destroy the currently emplaced alternative, and then move-construct that temporary _Tp into the new alternative (which hopefully won't throw). However, if we know that the _Tp is nothrow-constructible directly from arg, we'll just do that; or, if _Tp's move-constructor is throwing, such that the "safe" approach isn't actually safe, then it's not buying us anything and we'll just do the fast direct-construction approach anyway.
Btw, the assignment operator for optional does not do any of this logic.
Notice that for variant assignment, having a noexcept move constructor actually hurts (unoptimized) performance, unless you have also marked the selected converting constructor as noexcept! Godbolt.
(This experiment also turned up an apparent bug in libstdc++: #99417.)
string appending/inserting/assigning. This is a surprising one. string::append makes a call to __append_forward_unsafe under a SFINAE check for __libcpp_string_gets_noexcept_iterator. When you do s1.append(first, last), we'd like to do s1.resize(s1.size() + std::distance(first, last)) and then copy into those new bytes. However, this doesn't work in three situations: (1) If first, last point into s1 itself. (2) If first, last are exactly input_iterators (e.g. reading from an istream_iterator), such that it's known impossible to iterate the range twice. (3) If it's possible that iterating the range once could put it into a bad state where iterating the second time would throw. That is, if any of the operations in the second loop (++, ==, *) are non-noexcept. So in any of those three situations, we take the "safe" approach of constructing a temporary string s2(first, last) and then s1.append(s2). Godbolt.
I would bet money that the logic controlling this string::append optimization is incorrect. (EDIT: yes, it is.) See "Attribute noexcept_verify" (2018-06-12). Also observe in that godbolt that the operation whose noexceptness matters to libc++ is rv == rv, but the one it actually calls inside std::distance is lv != lv.
The same logic applies even harder in string::assign and string::insert. We need to iterate the range while modifying the string. So we need either a guarantee that the iterator operations are noexcept, or a way to "back out" our changes when an exception is thrown. And of course for assign in particular, there's not going to be any way to "back out" our changes. The only solution in that case is to copy the input range into a temporary string and then assign from that string (because we know string::iterator's operations are noexcept, so they can use the optimized path).
libc++'s string::replace does not do this optimization; it always copies the input range into a temporary string first.
function SBO. libc++'s function uses its small buffer only when the stored callable object is_nothrow_copy_constructible (and of course is small enough to fit). In that case, the callable is treated as a sort of "copy-only type": even when you move-construct or move-assign the function, the stored callable will be copy-constructed, not move-constructed. function doesn't even require that the stored callable be move-constructible at all!
any SBO. libc++'s any uses its small buffer only when the stored callable object is_nothrow_move_constructible (and of course is small enough to fit). Unlike function, any treats "move" and "copy" as distinct type-erased operations.
Btw, libc++'s packaged_task SBO doesn't care about throwing move-constructors. Its noexcept move-constructor will happily call the move-constructor of a user-defined callable: Godbolt. This results in a call to std::terminate if the callable's move-constructor ever actually does throw. (Confusingly, the error message printed to the screen makes it look as if an exception is escaping out the top of main; but that's not actually what's happening internally. It's just escaping out the top of packaged_task(packaged_task&&) noexcept and being halted there by the noexcept.)
Some conclusions:
To avoid the vector pessimization, you must declare your move-constructor noexcept. I still think this is a good idea.
If you declare your move-constructor noexcept, then to avoid the "variant pessimization," you must also declare all your single-argument converting constructors noexcept. However, the "variant pessimization" merely costs a single move-construct; it does not degrade all the way into a copy-construct. So you can probably eat this cost safely.
Declaring your copy constructor noexcept can enable small-buffer optimization in libc++'s function. However, this matters only for things that are (A) callable and (B) very small and (C) not in possession of a defaulted copy constructor. I think this describes the empty set. Don't worry about it.
Declaring your iterator's operations noexcept can enable a (dubious) optimization in libc++'s string::append. But literally nobody cares about this; and besides, the optimization's logic is buggy anyway. I'm very much considering submitting a patch to rip out that logic, which will make this bullet point obsolete. (EDIT: Patch submitted, and also blogged.)
I'm not aware of anywhere else in libc++ that cares about noexceptness. If I missed something, please tell me! I'd also be very interested to see similar rundowns for libstdc++ and Microsoft.
vector push_back, resize, reserve, etc is very important case, as it is expected to be the most used container.
Anyway, take look at std::fuction as well, I'd expect it to take advantage of noexcept move for small object optimization version.
That is, when functor object is small, and it has noexcept move constructor, it can be stored in a small buffer in std::function itself, not on heap. But if the functor doesn't have noexcept move constructor, it has to be on heap (and don't move when std::function is moved)
Overall, there ain't too many cases indeed.

Is move semantics in C++ something C is missing?

I have been searching for this matter on SO and other sources but I couldn't wrap my head around this issue. Using resouces of rvalues and xvalues somewhat new to C++ (with C++11).
Now, do we - C programmers - miss something here? Or there is a corresponding technique in C to benefit from these resource efficiency?
EDIT: This quesiton is not opinion based whatsoever. I just couldn't describe my question. What I am asking is that whether or not there is a corresponding technique in c.
Of course, there is a similar technique in C. We have been doing "move semantics" in C for ages.
Firstly, "move semantics" in C++ is based on a bunch of overload resolution rules that describe how functions with rvalue reference parameters behave during overload resolution. Since C does not support function overloading, this specific matter is not applicable to C. You can still implement move semantics in C manually, by writing dedicated data-moving functions with dedicated names and explicitly calling them when you want to move the data instead of copying it. E.g, for your own data type struct HeavyStruct you can write both a copy_heavy_struct(dst, src) and move_heavy_struct(dst, src) functions with appropriate implementations. You'll just have to manually choose the most appropriate/efficient one to call in each case.
Secondly, the primary purpose of implicit move semantics in C++ is to serve as an alternative to implicit deep-copy semantics in contexts where deep copying is unnecessarily inefficient. Since C does not have implicit deep-copy semantics, the problem does not even arise in C. C always performs shallow copying, which is already pretty similar to move semantics. Basically, you can think of C as an always-move language. It just needs a bit of manual tweaking to bring its move semantics to perfection.
Of course, it is probably impossible to literally reproduce all features of C++ move semantics, since, for example, it is impossible to bind a C pointer to an rvalue. But virtually everything can be "emulated". It just requires a bit more work to be done explicitly/manually.
I don't believe it's move semantics that C is missing. It's all the C++ functionality leading up to move semantics that is "missing" in C. Since you can't do automatic struct copies that call functions to allocate memory, you don't have a system for automatically copy complex and expensive data structures.
Of course, that's the intention. C is a more light-weight language than C++, so the complexity of creating custom copy and assignment constructors is not meant to be part of the language - you just write code to do what needs to be done as functions. If you want "deep copy", then you write something that walks your data structure and allocates memory, etc. If you want shallow copy, you write something that copies the pointers in the data structure to the other one (and perhaps setting the source ones to NULL) - just like a move semantics constructor does.
And of course, you only need L and R value in C (it is either on the left or the right of an = sign), there are no references, and clearly no R value references. This is achieved in C by using address of (turning things into pointers).
So it's not really move semantics that C is missing, it's the complex constructors and assignment operators (etc) that comes with the design of the C++ language that makes move semantics a useful thing in that language. As usual, languages evolve based on their features. If you don't have feature A, and feature B depends on feature A being present, you don't "need" feature B.
Of course, aside from exception handling and const references [and consequently R value references in C++11, which is esentially a const reference that you are allowed to modify], I don't think there is any major feature in C++ that can't be implemented through C. It's just a bit awkward and messy at times (and will not be as pretty syntactically, and the compiler will not give you neat error messages when you override functions the wrong way, you'll need to manually cast pointers, etc, etc). [After stating something like this, someone will point out that "you obviously didn't think of X", but the overall statement is still correct - C can do 99.9% of what you would want to do in C]
No. You have to roll-your-own but like other features of C++ (e.g. polymorphism) you can effect the same semantics but with more coding:
#include<stdlib.h>
typedef struct {
size_t cap;
size_t len;
int* data;
} vector ;
int create_vector(vector *vec,size_t init_cap){
vec->data=malloc(sizeof(int)*init_cap);
if(vec->data==NULL){
return 1;
}
vec->cap=init_cap;
vec->len=0;
return 0;
}
void move_vector(vector* to,vector* from){
//This effects a move...
to->cap=from->cap;
to->len=from->len;
free(to->data);
to->data=from->data;//This is where the move explicitly takes place.
//Can't call destroy_vec() but need to make the object 'safe' to destroy.
from->data=NULL;
from->cap=0;
from->len=0;
}
void destroy_vec(vector *vec){
free(vec->data);
vec->data=NULL;
vec->cap=0;
vec->len=0;
}
Notice how in the move_vector() the data is (well…) moved from one vector to another.
The idea of handing resources between objects is common in C and ultimately amounts to 'move semantics'. C++ just formalised that, cleaned it up and incorporated it in overloading.
You may well even have done it yourself and don't realise because you didn't have a name for it. Anywhere where the 'owner' of a resource is changed can be interpreted as 'move semantics'.
C doesn't have a direct equivalent to move semantics, but the problems that move semantics solve in c++ are much less common in c:
As c also doesn't have copy constructors / assignment operators, copies are by default shallow, whereas in c++ common practice is to implement them as deep copy operations or prevent them in the first place.
C also doesn't have destructors and the RAII pattern, so transferring ownership of a resource comes up less frequently.
The C equivalent to C++ move semantics would be to pass a struct by value, and then to proceed with throwing away the original object without destructing it, relying on the destruction of the copy to be correct.
However, this is very error prone in C, so it's generally avoided. The closest to move semantics that we actually do in C, is when we call realloc() on an array of structs, relying on the bitwise copy to be equivalent to the original. Again, the original is neither destructed nor ever used again.
The difference between the C style copy and C++ move semantics is, that move semantics modify the original, so that its destructor may safely be invoked. With the C bitwise copy approach, we just forget about the contents of the original and don't call a destructor on it.
These more strict semantics make C++ move semantics much easier and safer to use than the C style copy and forget. The only drawback of C++ move semantics is, that it's slightly slower than the C style copy and forget approach: Move semantics copy by element rather than bitwise, then proceed to modify the original, so that the destructor becomes a semantical noop (nevertheless, it's still called). C style copy and forget replace all this by a simple memcpy().

Is declaring variable with type inference as effective as "classical way" of initializing variable with parenthesis after variable name?

It would be nice to be able to easily text search in my codebase for places where is constructor of some object called. Here comes pattern bellow. Instead of classical:
Object val( a, b );
It would be nice to use everywhere:
auto val = Object( a, b );
That way I can use simple text search for "Object(" and get list of places where I am calling constructor of Object. It's also less syntacticaly ambiguous and therefore easier to make simple tools to automate some code transformations. It elegantly avoids "most vexing parse" issues too.
My only concern is about possible impact on performance. Is case 2) as fast a as case 1)? (If we can assume that Object has properly defined move constructor and move assignment operator and basic compiler optimizations are enabled.)
Pre C++17, it is possible, although unlikely, that you would get a performance penalty due to an extra copy or move. Even C++98 allowed implementations to remove such copies even if they would produce side-effects, and almost all compilers have implemented this optimization for a long time -- especially in optimized builds.
Post C++-17, copy elision is guaranteed. You aren't even required to have a copy or move constructor for this to work, so you shouldn't see any difference.

Class object creation in C++

I have a basic C++ question which I really should know the answer to.
Say we have some class A with constructor A(int a). What is the difference between:
A test_obj(4);
and
A test_obj = A(4);
?
I generally use the latter syntax, but after looking up something unrelated in my trusty C++ primer I realized that they generally use the former. The difference between these two is often discussed in the context of built-in types (e.g. int a(6) vs int a = 6), and my understanding is that in this case they are equivalent.
However, in the case of user-defined classes, are the two approaches to defining an object equivalent? Or is the latter option first default constructing test_obj, and then using the copy constructor of A to assign the return value of A(4) to test_obj? If it's this second possibility, I imagine there could be some performance differences between the two approaches for large classes.
I'm sure this question is answered somewhere on the internet, even here, but I couldn't search for it effectively without finding questions asking the difference between the first option and using new, which is unrelated.
A test_obj = A(4); conceptually does indeed construct a temporary A object, then copy/move-construct test_obj from the temporary, and then destruct the temporary.
However this process is a candidate for copy elision which means the compiler is allowed to treat it as A test_obj(4); after verifying that the copy/move-constructor exists and is accessible.
From C++17 it will be mandatory for compilers to do this; prior to that it was optional but typically compilers did do it.
Performance-wise these are equivalent, even if you have a non-standard copy constructor, as mandated by copy elision. This is guaranteed since C++17 but permitted and widely present even in compilers conforming to earlier standards.
Try for yourself, with all optimizations turned off and the standard forced into C++11 (or C++03, change the command line in the top right):
https://godbolt.org/g/GAq7fi

Which C++ idioms are deprecated in C++11?

With the new standard, there are new ways of doing things, and many are nicer than the old ways, but the old way is still fine. It's also clear that the new standard doesn't officially deprecate very much, for backward compatibility reasons. So the question that remains is:
What old ways of coding are definitely inferior to C++11 styles, and what can we now do instead?
In answering this, you may skip the obvious things like "use auto variables".
Final Class: C++11 provides the final specifier to prevent class derivation
C++11 lambdas substantially reduce the need for named function object (functor) classes.
Move Constructor: The magical ways in which std::auto_ptr works are no longer needed due to first-class support for rvalue references.
Safe bool: This was mentioned earlier. Explicit operators of C++11 obviate this very common C++03 idiom.
Shrink-to-fit: Many C++11 STL containers provide a shrink_to_fit() member function, which should eliminate the need swapping with a temporary.
Temporary Base Class: Some old C++ libraries use this rather complex idiom. With move semantics it's no longer needed.
Type Safe Enum Enumerations are very safe in C++11.
Prohibiting heap allocation: The = delete syntax is a much more direct way of saying that a particular functionality is explicitly denied. This is applicable to preventing heap allocation (i.e., =delete for member operator new), preventing copies, assignment, etc.
Templated typedef: Alias templates in C++11 reduce the need for simple templated typedefs. However, complex type generators still need meta functions.
Some numerical compile-time computations, such as Fibonacci can be easily replaced using generalized constant expressions
result_of: Uses of class template result_of should be replaced with decltype. I think result_of uses decltype when it is available.
In-class member initializers save typing for default initialization of non-static members with default values.
In new C++11 code NULL should be redefined as nullptr, but see STL's talk to learn why they decided against it.
Expression template fanatics are delighted to have the trailing return type function syntax in C++11. No more 30-line long return types!
I think I'll stop there!
At one point in time it was argued that one should return by const value instead of just by value:
const A foo();
^^^^^
This was mostly harmless in C++98/03, and may have even caught a few bugs that looked like:
foo() = a;
But returning by const is contraindicated in C++11 because it inhibits move semantics:
A a = foo(); // foo will copy into a instead of move into it
So just relax and code:
A foo(); // return by non-const value
As soon as you can abandon 0 and NULL in favor of nullptr, do so!
In non-generic code the use of 0 or NULL is not such a big deal. But as soon as you start passing around null pointer constants in generic code the situation quickly changes. When you pass 0 to a template<class T> func(T) T gets deduced as an int and not as a null pointer constant. And it can not be converted back to a null pointer constant after that. This cascades into a quagmire of problems that simply do not exist if the universe used only nullptr.
C++11 does not deprecate 0 and NULL as null pointer constants. But you should code as if it did.
Safe bool idiom → explicit operator bool().
Private copy constructors (boost::noncopyable) → X(const X&) = delete
Simulating final class with private destructor and virtual inheritance → class X final
One of the things that just make you avoid writing basic algorithms in C++11 is the availability of lambdas in combination with the algorithms provided by the standard library.
I'm using those now and it's incredible how often you just tell what you want to do by using count_if(), for_each() or other algorithms instead of having to write the damn loops again.
Once you're using a C++11 compiler with a complete C++11 standard library, you have no good excuse anymore to not use standard algorithms to build your's. Lambda just kill it.
Why?
In practice (after having used this way of writing algorithms myself) it feels far easier to read something that is built with straightforward words meaning what is done than with some loops that you have to uncrypt to know the meaning. That said, making lambda arguments automatically deduced would help a lot making the syntax more easily comparable to a raw loop.
Basically, reading algorithms made with standard algorithms are far easier as words hiding the implementation details of the loops.
I'm guessing only higher level algorithms have to be thought about now that we have lower level algorithms to build on.
You'll need to implement custom versions of swap less often. In C++03, an efficient non-throwing swap is often necessary to avoid costly and throwing copies, and since std::swap uses two copies, swap often has to be customized. In C++, std::swap uses move, and so the focus shifts on implementing efficient and non-throwing move constructors and move assignment operators. Since for these the default is often just fine, this will be much less work than in C++03.
Generally it's hard to predict which idioms will be used since they are created through experience. We can expect an "Effective C++11" maybe next year, and a "C++11 Coding Standards" only in three years because the necessary experience isn't there yet.
I do not know the name for it, but C++03 code often used the following construct as a replacement for missing move assignment:
std::map<Big, Bigger> createBigMap(); // returns by value
void example ()
{
std::map<Big, Bigger> map;
// ... some code using map
createBigMap().swap(map); // cheap swap
}
This avoided any copying due to copy elision combined with the swap above.
When I noticed that a compiler using the C++11 standard no longer faults the following code:
std::vector<std::vector<int>> a;
for supposedly containing operator>>, I began to dance. In the earlier versions one would have to do
std::vector<std::vector<int> > a;
To make matters worse, if you ever had to debug this, you know how horrendous are the error messages that come out of this.
I, however, do not know if this was "obvious" to you.
Return by value is no longer a problem. With move semantics and/or return value optimization (compiler dependent) coding functions are more natural with no overhead or cost (most of the time).