 So a little game for a talk on C++11 and how we make use of that in the LibreOffice code base. So yes, some kind of horror show, maybe, of things that you discover when you actually do use it and day-to-day work. So how did things evolve over the last few versions? I recovered that data from the mangas archives. I'm always bad at remembering at what point in time back then we started to use watch, so I think but I think I got it right that we started to move to C++11 in the for the for development cycle some very limited stuff that was then usable in the various compilers. So we're talking mostly GCC of course for the for Linux and for the old Mac tool chains and on the other hand the Microsoft compiler for the Windows tool chain and then there's Clang that we also use on Linux and there is no use on Mac exclusively. But Clang had the reputation for the best coverage of C++11 anyway, so that was never the the limiting factor. More severe was Microsoft compiler and to some extent GCC. So for the 5.0 development cycle we did boost up in what we wanted to make use of to clean up our code base and modernize our code base and then use features very useful. So we decided on a GCC 4.6 and Microsoft compiler 2013 baseline sort of thing older it was not able to build the office and we got a kind of sweet spot of things we could start to use. This is mostly taken from the advertisement pages of these compilers or they claim to support. In some cases you have to be careful and their support is not really for example the defaulted functions in the in Microsoft compiler are still as things still in the 15 version they're not really there so they have some really major support for that almost full. And then we iterate this for all the whenever we spawn off the so when we spawn off the 5.0 version from the trunk code base we decided for example to drop 4.6 GCC 4.6 support because Unique let us allow this to do that. So we gain some more features there next step probably will be to we are now in the process of making the code but work with a Microsoft 2015 compiler there was some work needed there must be done by Davidov Trawski. So at one point in time we'll switch from 13 to 15 for sure. If any of these features on that list there if that is great to you there's two resources that are vital one is this book why it read it the other is don't be shy to actually look into the standard you can download it from github it's the tech file so you can lot take it look at it send in patches but I don't think they they are so eager about patches so they not sure they will be greater easily at least mine okay so let's start with a rather easy thing first the other introduction of the auto feature so that you don't need to declare the types of your variables anymore and that the compiler deduce that cool feature paired with this other new feature of these range based for loops where you don't specify for I from begin of vector to end of vector and then incremented in each step much more cheers way of now if V is any kind of data structure that has a begin and end you can iterate for all the elements now and I is no longer a pointer to that object in the vector but is the the element itself and that is whether the danger of this auto lives because what happens in the first line I use a reference to that fat class member in there what happens there we do a copy construction so for every iteration through the loop this I is of type fat class and we copy the member out of that vector and then can work on it most of the time that's not what you want to do so that one pitfall with the auto is whenever you do the auto in a for loop you probably want to use a reference there or if you don't go to to manipulate it in any way make a cost complete and at the cost there so what happens beyond the scene with this auto is the same thing that happens when you have a templated function with a template argument of party and then you pass in something then the compiler also deduces what that T might be given on what you pass in there and exactly the same mechanism is used to deduce the auto that is because what you get out of here is a reference to that element but as would be the case in the in the function type deduction it doesn't deduce reference to fat class what it does reduce deduce fat class so you need to to help with a long kind of there to not fall into that trap otherwise both features auto and range based for loops very useful already to clean up lots of our local so there you go yeah let's get a little more into the scary parts that's kind of a sequel to what I had this morning with a destructor that unexpectedly throat something this is another example of how to have a destructor that does not throw wise do what you would expect you to do I'm sorry the lower part of the slide but there's still space in front so no excuses and so what do we have a function that's close something we have another function that calls that function that throws so that will of course as well throw we have a structure that has a destructive that calls that function that throws so yeah the destructor will throw we have one more function that has a try catch block so whatever get thrown in there will be caught everything fine when we pass in true we go into this branch where we call that function that throws so we throw we catch everything good when we are in the old C++ 03 we pass in the false we create this as instance we destroy it immediately again go into the destructor call the throwing function from the destructive throw get caught leave age nothing happened but C++ 11 destruct there what happens terminate and or exit oh why does it happen because you didn't read the manual that's why it's all go read that standard and go understand it it's not that hard to understand so this destructor it didn't have an explicit throw specification so what happens the compiler gives you one an implicit one and the implicit one will look the same as if the compiler had to generate the whole function so if you do not specify the destructor the compiler will generate one for you that's all use and in the case of a destructor in C++ 11 it will generate one that has a throw statement throw specification where it looks at all the member variables and all the base classes so no member variables no base classes easy case the throw specification would list all the exceptions that may be thrown on the base class destructors from the member variable destructors is none nothing may be thrown so this innocent constructor is in fact the most constructed now even though you didn't write it the semantics changed there slightly so what now happens is that if we reach that destructor of the S instance we throw something destructed that's done pro so called standard terminate which then throws your lovely deeper office instance into the bin yeah so that's something to be aware of but it's always a bad idea to throw from destructors that's true since forever unfortunately our code base has some cases where we do do stuff in the destructor like this was the case that unburnt this problem where we have some OO XML footer handler whatever during parsing of the mal documents we did some stuff in the destructor and it was now the change to instead of a finalized function that is called before the structure gets called and whenever something does happen in there and get thrown then we don't run into this problem sorry yeah because of throwing this structure is always a disaster so when you're on a when you're on a code path from throwing somewhere deeper down in the call stack and you pass through that destructor during the second one you abort as well so that's what I said it's always been a better idea to throw from destructors so well we have code wouldn't have noticed that semantic change in C++ 11 anyway and I think that's the only reason why they got away with that kind of change another example so there's this nifty Q you feature having a function or in this case the constructor that just forwards all its arguments it takes whatever arguments you have and forwards it to somewhere else so strap down that is some kind of record class for some type T and so you can construct a record with whatever arguments can you mention and arbitrary number and it constructs the T instance and then forwards all the arguments into there so what did you do in the past about something like that all you you estimated that your function will not be called with more than six say arguments so you spelled out six overloads overrides overloads of that function and yeah I believe coached application no longer needed but now come the problem you have some code that uses such a wrapper around some class X and you make that export that from the library and the poor Microsoft compiler then starts to screen with a very odd error message that it cannot instantiate the T constructor with a rep T argument yeah what that the thing that happens is that because this one is exported from the GLL there was semantics of the Microsoft compiler to instantiate all these implicitly generated functions for this rubber class instantiated on X so this doesn't have a copy constructor explicitly mentioned so there's an implicit copy constructor if you don't use it normally it would never be called maybe you don't even want to have this wrapper class to be copyable but the helpful Microsoft compiler thinks I must emit that function from this GLL so I must generate it another problem is so I want to have a I want to have a copy constructor for s that needs to copy that member X of type rep X I don't have any explicit copy constructors here all I can do is I have this wonderful constructor that takes any kind of argument any number of them but I can have just one argument that is a rep X conference reference and because I need that for my copy constructor and then form up that into the construction of the team or or X in this case of instantiation but there's no way of constructing an X with a brother around X so to help the for Microsoft compiler out of this it wanted to generate a copy constructor for s which has a rep X member we tell it rep is not copy constructable so how do you do that in C++ 11 you have the copy constructor and you define it as deleted but the compiler knows you never can call it the Microsoft compiler then smart enough to see are I have a class s that has a non-copyable member so there's no way to generate a copy constructor for class s we thought it doesn't generate one it can't now knows it didn't try to go that wrong route of going through the forwarding constructor but now you write some innocent code where you have to wrap around X's X1 X2 and by accident you assign one to the other but the copy constructor is deleted this code should not compile should it yes it should X1 is not const so we use that other copy constructor that takes a non-const reference to rep and creates a copy from there or in this case here is the design and I should have written that something somehow differently so that the copy constructor will be called the copy design sorry the idea is that this piece here can stand in for arbitrary versions of your copy constructor the one that takes a const reference or a volatile reference or a const volatile reference or a plane reference so to make these lower lines not compile either you need to actually write two different copy constructors into your class and that's when the Microsoft compiler starts to complain there's a class that has two copy constructors are you sure yes I am sure and we have to silence that very hot warning that's probably a leftover from before foreboding functions that now actually require you to sometimes write more than one copy constructor and this is the commit where we needed to add that to this VCL pointer feature that Michael talked about earlier and if you actually read this book the bonus is that it gives you probable material to write to your commit messages because yeah this is so okay so crazy nobody with their right mind would want to know about it another thing somewhat easier again not stress you too much scope cool thing the classes that you now have that you can't wrongly mix with integers so you can't take any not value to stand in as an integer so for the original in us every name value could implicitly be converted to an integer so that you could have culled but somewhat dubiously multiplied a color in them and whatever in them and and got away with it without any warning so there's now these scope denims where you have a real new type that is distinct from integer types and that it does not implicitly decayed into the types but so you have to switch over all the all the enumerators you have an exhaustive exhausting switch so there can't be any other case here you either have any one or really to your function that's a return something in both cases with return something do we need that default statement or is that some soil defensive programming mistake turns out yeah strictly speaking we do because these scope in us is still as bugged as the non-scope ones they are distinct from the underlying integer type but they still have an underlying integer type and their value range is still the whole underlying integer type so if you don't specify an underlying type into this assumed so this e cannot only be one or a two it can be each arbitrary integer so you still have this problem that static code analysis tools should they warn about this that there is a missing return statement for all the other cases or should it assume that yes your enum can truly only contain these two values which is your intent so there's there's some some of the tools are going by the rules and assume that you do need an additional statement or else would warn that you have a code path where you fall off the front and that and read that do not return anything and some other tools some all take the blind but intentionally better route of thinking that if you have an enum class that only has two members and these are the only two values they will put in there that's another thing to watch out for or to understand if you're compiler rather static analysis tool tells you something about such a case where you say but I know that you can't be true can't be right and one more thing which only tried to riddle me with last night you have a vector you have some make up some struct for class that has a destructor that does something well the easiest thing to do something is to print out something so you have a value member and print it out in the destructor you create that with one or two and three then you erase the second element the idea being you remove that one from your vector so that needs to be deleted at that point so you assume that between these two lines of dashes the destructor of the second element of the number two will happen so what will be printed the two should be printed or should it a three gets printed broken broken by design or did we do something wrong with that begin now it does point to that second element there's also some printout before that that's because you create these as temporaries stuff them into the vector and then the temporaries from which the vector elements got copied they are destructed to generate it first then we have that magic erase that does print a three and afterwards we destruct the complete remaining vector and then remove and erase the one and three again why is there and that's what you expect but why is there this three in the middle well what actually happens is that this put struck s does not only have the destructor but also it has these implicitly generated members among them there's move assignment operator this one here and now we'll print out something in the move assignment operator to make the code compile we need to also declare all the others because if you declare one of them explicitly the others won't be generated implicitly so you need to default those others to make the code actually compile again and now if we rerun that what do we say first part remains the same then we move the number three element over the spice where the number two element was so we do not delete the number two element because we reuse that spice and we just suck the lighter elements one one one earlier so what we actually do delete is the number three that we freed at the end and its content is by then already moved into the one earlier so everything is fine again we do not lose any number of destructors so we don't call too little to few of them we don't lose any data we just move over I say that's why or not because I cheated because this one this one has a destructor so it an explicit destructor so it doesn't have an implicit move assignment operator because if you have a destructor explicitly mentioned then the compiler won't implicitly generate any move operators for you so what really happened and already happened in C++03 so this is nothing nothing new with C++11 so what really happened is that we didn't call the move assignment operator to carry the data forward one element but the copy the copy assignment operator so we copied the last element into the one month last that originally contained the two but the story remains exactly the same when you erase from an element from a vector you do not delete the element that you erase but you actually in fact delete the last element and all the others get copied or moved over in place so that's what might confuse you if you're waiting for this constructor destructor to be called for the right element and that doesn't happen that's why okay yeah one right I'm using thing at the end this cleanup stuff of moving ever moving more and more modern C++ features there's not not anything new we do in the code which is by chance the couple of days ago discovered in the code at least 10 year old attempt or it must be even older 15 years say attempt at using unnamed namespaces which by then were not available in all the compilers so what we did there is have a name to name space for the very strange name to fake namespaces and I finally threw it out there were three more occurrences of that still in the code base so it always or it's never too late to actually clean up the dump fake attempt from the past and use the good new great stuff and that's it we are running over time I see so no questions quite a great question yeah given that we in many cases have ref counting on of our own on them there's I think not that much benefit might be might be some but always upon as well I think it's not that big a win but there might be cases where where we have areas in the code where we would benefit but not in the overall case