Back to Basics: Iterators in C++ - Nicolai Josuttis - CppCon 2023

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the networking opportunities here at CPP con are well above and beyond any other CP C++ conference that I've ever been [Music] to welcome everybody hello my name is Niko Niko yotes and I have the honor to talk about iterators something I think I first did 30 years ago um it is um that C++ is well a big part of my life as I've written a couple of books about it and giving trainings a lot of times and I was also involved in the C++ standard standardization and I still am so it's partially all my fault um so here in this talk and we want to get back to basics because well over the is it hasn't become easier to learn C++ um so Basics which is we have to talk about iterators which play a key role in C++ it's probably one of the features that may made C+ plus a success story so when we Loop over an array the ual thing we learned in programming was you can use an index so we can use some index counting here from zero to three and then print the elements in this array which you see there on the right but there's another way to do that and this other way is already available in the programming language C which is um you can take the addresses of the elements so-called pointers and the array itself can be used as a pointer and array + 1 2 3 4 are the next one two second third element and you can initialize a pointer with the array and then iterate over the array until you hit the end as I said that's already available in C but it was um the basics of an idea that we want to abstract this idea not to be a able to iterate over elements even if they are not in an array please note that uh the last position the position I compare against is valid to use although the element the value there is not there's already the next object starting so don't use that memory if you if you use that address array plus 4 that's fine but don't go to the value there that's an important principle which we will also find in iterators so iterators are an abstraction of this idea so if you take this idea to iterate with a pointer over the array let's do and try to be able to do that everywhere let's do that in a vector for example here but how do we Define the address of the first element and the address behind the last element to write the same code well we introduce some member functions and these member functions are begin and end so by asking the vector where's the beginning and where's the end we can do more or less the same as we can do with the pointer we can use something that is able to iterate over the elements of this container it has its own type in this case case it's an iterator type of an SD Vector of in um we will see later on why we have different type or specific type for that so same you can do for example for string so we have begin and end also there defined and we can use an iterator uh we get it with begin and we initial and we iterate as long as we are less than the end go always to the next element and if we need the value we use the star operator good so far so good um that was the beginning um 30 years ago now these days nobody write that code that's far too much typ characters to type so let's use Alto here um in general it's not the recommendation that you use all the time everywhere Alo but more and more we do especially if we don't care for the exact type we know that with begin we get an iterator and what the exact type is does not really matter so here Alto is a perfect example for useful application please note that we still have the principle here that the end is not an element or at the end there's not an element it's a position right behind the last element so why we call we say this is an half open range it includes the beginning but it does exclude the end so why did we do that why was that designed that way well first of all the consequences as you have seen before you can use the end position but not the value there don't do that that's defin Behavior there is something but you never know what it is and how it behaves so why do we have that with that we don't need special handing for empty collections so in an empty collection begin equals to end and the loop you see there still works we initialize with the begin while we are less s the end we iterate over the elements well we are immediately um equal to the end and so this Loop does nothing and works for empty collections okay now see you've seen the principle of what is an iterator why do we have them here's an example of one container we have a container is kind of a data structure we have in the C++ standard so we can put there many elements and and they are stored in some way a vector stores the elements in continuous memory so as you see here um we have a core object where we know the size we know how much memory we have allocated and we have a pointer to the real raw memory where the elements are stored which is usually on the Heap that is where you get your iterators from so when you start to iterate over the elements of this Vector you are pointing you referring right inside this Vector at some specific location so when we now asked this Vector give me the fourth element that's a cheap operation why is it cheap because how we use that is we go to the begin and then we Advanced four elements which we can compute easily because we know the size of each element and as all the all elements are in continuous memory it's easy to compute where the element is but we have other data structures in C++ so one other data structure is a linked list a doubly linked list it's called STD list so here it's not that all the elements are in continuous memory here it is that each and every element tells you where you find the next element each element has a pointer to the next element and by the way each element also has a pointer to the previous element it's a doubly link list it using a list has some benefits uh which we don't have to discuss that it's just one of the data structures we have now think about we would try now to use the index operator here to access an element that would be an expensive call because we cannot compute where the third or fourth element is we have to go to the begin so the first element ask where's the next element to have the second ask where's the next element where where's the next and ask verus for the next element to get the fourth element that is an expensive call and you know what one reason we do C++ is because we don't like bad performance so what is the consequence well don't do that we could do don't do that we could say don't do that but in this case we want to protect protect you from yourself as a programmer so we decided we don't offer this operation especially as if you iterate with an index over the iteration what happen happens is each time you use the index operator you go to the beginning and then you find your element the first time it's only begin the next time is begin to the first element the next time it's begin to the first and second element and so on and so on and so on so finally if you have 1 million elements you call begin and then 1 million times follow a pointer to find your element that would be a nightmare just to read exess the elements with an iterator it's better with an iterator we can start at the beginning knowing that we iterate over the elements just follow all the time only to the next element go to the next element so this has significant better performance and that is the only possible way for all our data structures to iterate over all elements so the basic way to deal with all elements and some data structure is call begin and then start to iterate with what you get back as long as you are not at the end for the next element you call plus plus for the value at this element you call Star that's the basic heart of of everything in C++ as soon as we deal with Collections and data structures and that is obviously a perfect example for function template because this function template would compile for all the different types we have you see on the right some types we have you saw already vector and then doubly linked list but we have even more complex data structures like like balance binary trees or on the bottom right you see hash tables they all work with this API which means as it is a template we don't compare this code in a in a way that we have a generic pointer finding the next element it's generic code that once we know for Which object for which collection we call this for we compile this so for example We call we compile Pi in the first call of print alms we compile print LMS for an ACD Vector of in and the interesting thing is that the plus plus operator here is specific implemented for INS that way it will just go ahead to the next memory adjusting the address by the size of an end if you then instead use a balanced binary tree which we have here it's called a set then uh what we do with Plus+ we navigate to the next element which can be pretty complicated the next element is um on the right sub tree the leftmost element or if there is no right sub tree we have to navigate up and take that element there so that is essentially what happens if you call Plus+ which obviously makes Plus+ a little bit more expensive but the point is we can easily iterate through all these data structures with the same code and as we have templates instead of one type doing everything for us we decide how to iterate at compile time and that means compilers can optimize at compile time so they can see the way we iterate through this data structure like a balanced binary tree and optimize whatever they can to make our code as fast as possible okay so this is a way we iterate through all the containers there's a shortcut for that available since C++ 11 which is a range based for Loop which we could put in a function template but under the hood the range based for Loop does exactly what you see above so the range Bas for Loop calls begin and end to initialize an iterator to iterate over the elements until we are at the end and C++ Tren there's a new way to write that instead of using a template parameter you could write Auto here that's only syntactic sugar very nice syntactic Suter you could also qual constrain this type in some way saying this has to be arrange to improve error messages but again this is syntactic sugar at the end you're using iterators to iterate over all your elements of the past collection sometimes we care in C++ for conness so we have a keyboard called const well why did we have it it's it's not to make your life hard it's to help you to find bugs at compile time so the keyword con helps us to say it's my intention not to modify anything and with con you can protect yourself that you not accidentally modify things where you don't want to do that to support that idea if we iterate over the elements even if the con container is modifiable we introduce the type for each and every um container class which is called the const iterator type and by definition that means if you the element it's const which usually means you cannot modify it you can screw that screw that up in C++ so that means if you try here for example to assign a value there that will not compile we also have support for alutto here because um if you want to use Alto because it's so much stuff to type to declare the exact iterator type then um and we still want to have a cons iterator we introduce something called C begin and C end it's just a helper to make sure that if it's working like begin and end but returns a const iterator so it has the same effect you protect yourself from not accidentally modifying the elements this by the way is partially broken by C++ 20 and 23 views be careful a little bit with that I don't explain that now now there's some one important thing to learn here I told you already that you we want to protect you from doing something bad regarding performance and that applies for example by not having the index operator available unless we can directly jump to an element which we call random access we can randomly access to the 100th element for example we do the same for iterators we protect you from doing something with iterators which is which is has remarkable bad performance and for that reason we have different categories of iterators it's It's iterators have any way different types but we categorize these types in a way that we say with some iterators you can do more than with others so one category is a random access rator category and as a nam s it allows Random Access you can jump directly to another position for example we support plus equals plus equals you can say plus equals 100 and that means Advance 100 elements and we provide that because for the containers we provide that we can compute where this element is for example in a vector we know where it is this is not the case for all the other containers in all the other containers we cannot compute where the 100th next element is we can only 100 times go to the next element so as a a consequence we say well these iterators if you if you iterate over these data structures they cannot do plus equals and there are a few other things they cannot do for example you cannot call less than you cannot easily compute whether one element is before the other which is easy if you just compare the addresses but a link list in a link list or in a tree the elements can can be spread all over your memory so there is no way to easily find out whether one element is in front of the other or compute the distance between two elements that's all not supported so if you still can go forward and backward it's called the bidirectional iterator so um but there might be containers where you can only go forward H we have that for singly link lists they have no back Link in each other and hash tabls by the way also have uh on theat rators where you can go forward the reason is that in hash tables they internally use Link lists you see them there it's an area of Link list and that linked list can be a singly link list so therefore we don't have that bidirectional iterations there there's in principle another category where we not have an an an an obvious container for which has an interesting constraint um and all these iterators you see here if you are at a certain position and you have two iterators pointing to that position and you advance them once go to the next element they find the same element so we say they are equality preserving what is not the case in an input iterator input iterator is a tricky Beast which means we have the interface of an iterator but the way we use it is that we read for example from standard input so if you have two objects of that and they both use standard input and one goes ahead one element which means we read one element and then the other goes ahead one element they have different values because one reads the next element and then the next one reads the other next element so they are not equality preserving and we call them input iterators so what this semantically means is you can safely read the elements only once you might have to care for these categories in your code so for example this what you see there on the top is code that does not work that does work with each and every container because all the iterator categories we had they provide this minimum set of operations the blue ones guess you want to print every second element and you can could can start with this code this code is a little bit more complicated and it's not that easy as you think at first so um you initialize your position with a begin and then let's iterate with plus equals 2 each and every time well I told you plus equals 2 is only available for Random Access iterators so therefore this will not work for other containers but there's another reason why this does not work it's less than so because we have to deal with the problem we might jump over the end so we go to the last element and then we call plus equals two and we jump over the end we cannot use not equals so we have two reasons we cannot use an uh something like a link list or balanced binary tree or a hash table so that Cod even if it's generic does only work on a restricted set of data structures who have this requirement we have a requirement here we need a random access well you can fix that you can write this code differently so you could make sure you only need the basic operations of um all iterators so you see we now switch to not equals and instead of calling at the End plus equals 2 we call plus plus pause at the end of the body you could also do that on the right hand side of the reinitialization area that's depends on your style the important point is to make sure that because we only compare with not equals against and to make sure that we don't jump over the end we have to say and when after Plus+ we are not at the end let's do one plus plus again so that way we can iterate over every second element but we still make sure we find at the end okay good and by the way what you just saw is a reason you should not use a less than sign here in this basic Loop because less and does only work for Rand access iterators so that is really the basic way to iterate over the elements just a hint here inator categories have changed in C++ 20 we have a new category so there's a category called continuous iterator and we we have corresponding categories for the ranges we iterate over so continuous range Random Access range Etc so why did we introduce that and what is the difference before everything above bidirectional iterator was a random exess iterator now for continuous iterators we have a special group and that means all the elements are in continuous memory so the reason we have that is that for these iterators we can do something special so for example we can internally use raw pointers because we know that all the elements are in continuous memory or we could also convert the value the array the internal list of elements uh into a into a raw C++ C array by calling a data a function like data that's possible there that's not possible for Random Access iterators which are don't have continuous memory there's one example exactly one where we have that it's called the deck because a deck is internally using an array of arrays so we can still compute where's the hundreds element but it's not just adding 100 times the size of something we have with the 100 we have to see um how many arrays do we have internally and divide by their size and then we know which area to take and then we can jump to the element so it's still fast to find an element that's why we have random excess but they are not in continuous memory okay these are the basics and with these Basics we um came up with the fundamental programming model that made C++ a success story we came up and said you know we have different data structures we call them also ranges uh we Implement them as containers and then we have algorithms that work on them and instead of implementing all the algorithms for all the containers with all the different types let's implement the algorithms once using the same API which all the containers provide which are the iterators so iterators is the key glue Cur to bring together different data structures with different algorithms so for example we have a s algorithm the sort algorithms you pass a beginning and end before you came to C++ 20 at least and um that will internally sort the values of the elements sort for example needs random excess because um they jump back and forth but between all the elements in this data structure so s will only compile and work when the data structures are random access iterators h Random Access ranges or use Random Access iterators or better I should say since C++ 20 because we have the continuous category here's another example Max element let's search for the maximum element which is a little bit funny it's a generic algorithm that works everywhere a set sorts the elements automatically so there's an easier way to find the maximum element it's the last element but you can still call this because in all the other containers you might not find it right at the end there might be none so that's another reason we have half open ranges if there's none we return the end position saying there is no element found well how can we not have a maximum element if the collection is empty yes here's a numeric algorithm let's accumulate all the elements um and add them to an initial value zero here here's how it is implemented the generary code using these iterators so you see accumulate takes on the top at the top begin and and let's defin the range including the first element excluding the last element and then the starting value and internally we do what you just learned is let's initialize an iterator iterator initialize with begin why we're not at the end go always to the next element and add the countr value to the existing value so we can use that for Vector of long values and we get the sum of all the long values in this Vector as this is generic code it works for all the containers for all the data structures and for all element types as long as the element types understand plus so um you could use it for strengths so just for fun create us initialize a set of string with the elements 1 2 3 and four written out there a spell out as a string and what is the output think about think a moment what is the output we start with an empty string there so if you think the output is just one string having the value 1 2 3 4 inside that's wrong this slide is a trap because set sorts the element so the output is 4132 of course but the principle reminds okay please note that in this principle where we bring together algorithms dealing with containers and different data structures using the iterators as glue code here this uh works with the idea of pure abstraction you will not find a base class for all the iterators you will not find a base class for all the containers the principle is everything that behaves like a container is a container everything that behaves like an iterator is an iterator so what behaves like an iterator and can be used here is raw arrays or pointers pointing into the horor array so you could declare an array of um doubles here and then pass array and array + five array as the address of the first element aray + 5 as the address behind the last element and that works because what we internally do with this pointer is we uh call Plus+ we call not equals and we call St to get the value and that works so that was key a key element of this design the and at that time when this design was developed that was in 1998 well in 1998 we shipped the standard so it was developed in the '90s that was kind of a revolution in a way that we didn't follow the other Revolution because that was where everybody said you have to do everything objectoriented and when you have everything object oriented you put together data and behavior and functions and so but we separated it we say oh no we have the data and then we have the function the accumulate it's separated so everybody said you're absolutely crazy to do that you didn't learn the lesson well we learned that's this is a different Paradigm this is generic programming not objectoriented programming and it was the beginning to learn that one of the success stories of C++ is that it is a multi Paradigm language we use to write Paradigm to program for the appropriate problem of course we use inheritance when it is important which is not so often the case by the way okay there are caveats there are pitfalls they are traps so in other words you can do something wrong let's look at this example let's use iterators of vectors if you create such a vector I told you already it looks roughly internally like this we have a size a capacity and data pointer and the data point is referring to where we store the values we are have currently in this container which is usually allocated on the heat so that is what you get with this declaration and initialization when we iterate over this using a range based for Loop the race bench for Loop uses iterators to iterate from beginning to end so the vector has begin and end and that is used by the range base follow to iterate over the elements and what you get while you iterate is the element for that the range based for Loop internally calls the star operator so now let's find the first element with the value eight we have one so we point right in the middle of this um data structure or refer to it and please note that this also works if we don't have a vector if we have other data structures like balance binary tree or so that code is generic we refer with some type to some element in this V Vector now vectors have a special ability they guarantee that all the elements are always in continuous memory well which is a problem when we add a new element and we already have used all the memory we currently have so the capacity as we say is equal to the size so oh I forgot that before I say that yeah you can use that iterator to um print out we have one and modify this value for example to double the value that's fine to do so now let me come back to the point and let's add a new element here the vector needs more memory to do that the vector reallocates and that means uh a couple of things happen so first of all we have to allocate more memory well the vector has to do which it does by some policy so they might double the size or some other implementations at only 50% of the size that depends on the implementation we have no guarantee in the standard how exactly memory grows so here we double the the memory so we have capacity for aen elements now we need all the existing elements in the new memory so they are moved and the new element is STO if these are strings all each and every string is copied or moved because we no longer need it at the old location in the old location we can destroy them and we can free up the memory there which unfortunately is used by posate so if you now say oh let me modify posate by two again multiplied by two that's undefined Behavior well this memory might now Ed by something else and you modify this something else which can create trouble deep trouble if you have a Corum you're lucky because you see that something goes wrong it might just change your string with your key to encrypt the data or and that might be worse and of course only if you delivered it to the customer your tests work fine that's a fatal runtime error undefined Behavior it's your task to reinitialize posate or no longer use it why don't we do it automatically performance there are other things that can go wrong look for example at this this is a transform algorithm it reads all elements from a source transform them in some way for example here we squared we can use a function or you can also use a Lambda there and then write all the elements to destination well if you have that there's some important thing to know the writing it Ator overwrites the writing iterator writes at the location it is currently at and then goes to the next element this means if we compute squares from a couple of input values there have to be room for the output values unless otherwise you have undefined Behavior so think think about you make the following you say my sauce has six elements my destination is empty that's a fatal runtime error again undefined Behavior here's the point your Source has a usual beginning and end your destination is empty you call transform you iterate reading from The Source you iterate writing at the at the destination but there as is no memory you overwrite other data not a good idea so for example what you could do is you can resize not reallocate reallocate only allocates memory resize really means there are valid values which I can't overwrite and say here okay let's first make sure we have enough elements to overwrite yeah that's not the best way to solve it but this works that's not broken there are other ways to do that one another trick is to use a very clever special iterator which um is called an inserter well and back inserter and now we come to the magic of this Library everything that behaves like an iterator is an iterator so what the back inserter does it says oh you want to write a value and then you want to adjust to the next value so for me you call plus plus and then with star you store value the API of this back inserter takes that to say okay you know what if you call Plus+ I do nothing if you then call Star value equals something I call push back well for that I have to know what to call this push back so the back inserter needs that that is one iterator which needs the destination the container that is a trick to solve this okay it's still a valid iterator and we insert the Val Val as they are finally what is the output of this program that's a third caveat that's a collection let's print all the elements which has these values inside the threes are marked because I want to remove them and there's a remov an algorith algorithm that REM remove them let's remove these elements now let's print the output again and let's print out the content of this collection the output is this to some extent threes are gone but there are still as many elements as before why why removing algorithms using iterators cannot remove because an iterator cannot remove all the iterator can is go to the value read it or write it and then go to the next value unless we have something special like a back SATA which cheats with this API so what we really do what the iterators or what these algorithms do here um there is a reading iteration on the top with the blue and then the writing iteration on the bottom that is a outcome for the removal and then when we hit the three we say oh let's move the two to the three and then therefore the one to the two and then the one to the previous one and then the two to the one and then the oh no the three we want to skip so the four to the two and the five to the three and the six to the four and that's my new end then and let's leave the others alone so the way this works we can only because we only can read and write and go forward and backward and jump around that is the only thing we can do naturally you can also not change the size of an ARA with a pointer it's the same thing just pointing to one element I mean so as you saw there's support you get the new back new end and all you do is you iterate then from beginning to the new end and print out all the elements and voila you have the effect you want can we do better yes this is basic that's more or less C++ 98 if I have there on the right top I try for each and every slide now to show with which valid it gets with which version it gets valid because we have so many C++ versions so this essentially means this is this is contents of C++ 98 C++ 11 is only used because we use AO and for initialization with curly bra is some syntactic sugar so yes you can still use the range based for loop with C++ 20 because in C++ 20 we come up with ranges with range support and Views and what you can create is something that is defined by two iterators but behaves like a range but does not create a copy of everything it just refers to the original data so this is what we call a sub range a sub range is kind of a view we say well this is a range starting with begin going to end to the new end and you can use this sub as each and every iterator um container so you can call there again begin and end and Plus+ and it works so that is another way to do that well there a third way to do that if we switch to C++ 20 we can even make it even better we can say oh let's not modify the container at all let's print out all the elements except the threes or if printing is just an example let's process all the elements in this container except the threes the way to do that is to use a filter so you see this syntax very nice to use now that is a collection is piped into a filter and the filter has a predicate saying well I only accept elements that don't do not have the value three p year is a Lambda okay what is going on here what is going on here is that on top of the collection you place a view the filter View which is just which just refers to the collection and has this predicate saying I don't accept threes so the effect is interesting the effect is so that we say well look at this example this shows a little bit in more General where this the effect so we have a slightly different Vector 185 4 7 1142 and we search for the elements greater than 40 the idea is as a vector has an API to provide iteration to support iteration and then the iterators you can use by calling Plus+ and star and other operations depending on the category for a filter we have the same the filter refers to the container and provides the same interface now if the range based for Loop CS begin here then we go to the view the view says oh you want to have the first element good now let me tell you that I I will find it on my reference collection let's begin but but wait a minute we have a filter here um the first element I cannot accept so that's not valid so you are for begin you want me to give you the first element well what I call is I call begin to go to the first element and then go to the next element oh that's an eight also not okay 15 also not okay 47 oh yeah that's it that is what you return in this call what the viewer returns as the beginning what you get here is an iterator an It iterator of the view and the iterator of the view uses internally the VOR to radar so the same principle is still used but it's it's hidden let's print the value okay let's print the value we have the element go to the value print it let's go to the next element well that's easy we call Plus+ we have our iterator and now the iterator has to continue to iterate in the vector to find the next element with a value greater than 40 which is 42 we can print it out and we do that until we are or as long as we are not at the end that's how views operate okay in the design of a filter there's an optimization the optimization is once we found begin so with the first call of the begin here you say oh wait a minute you know what I might later on do another iteration over this collection so let me cash begin so because yeah processing especially pipe processing might mean afterwards there's a pipe element that calls begin multiple times so we have multiple passes to iterate over the elements so it would be expensive to iterate each and every time to the beginning especially if the G is not right at the beginning so that's the consequence of that design the consequence is clst demos this example it's a ordinary generic print function in C++ 20 you can use Auto instead of a template parameter that's syntactic sugar more interestingly is yeah we can pass a vector of in in the list of in good we can print out the values we pass the container by reference con reference so let's do what we just saw let's um now iterate over the vector using this filter yeah we create exact the behavior we wanted now when we iterate we print out all the elements greater than 40 awesome works now you call print with this pipeline you get a compile time error oh what the hell is wrong here well you can see it know it if you carefully think about what I just told you when print starts to iterate it calls begin begin caches begin is cached that means we modify the view so as a result this Con here on top is an error it's a problem so therefore it works without passing to print but it does not work when we use print that has a couple of bad consequences and it's even worse there are other views where sometimes they cach sometimes not so when you print a vector and you say let's skip the first three element that works when you skip the first three elements and it's a list below it does not compile I consider this to be a design mistake of views but it's important for you to know this so you can also say this is a feature one last example what the consequence of this feature is let's define that we only want to have from a collection all the elements that are even let's iterate over them and that use that to modify the elements which l in principle allowed yeah so um 1 14 710 becomes 1 16 712 awesome let's do it again awesome works good now let's add one instead of add two okay four becomes five 10 becomes 11 we have no even elements anymore so next time nothing happen oh oh the five becomes a six but the 11 doesn't become 12 yeah because we cash began so that's the first element we C we we process and then we look is there any else anything else none is there yes that's the standardized behavior of filters in C++ 20 it's not considered a back it's an optimization for multipass containers and we know that this is a problem so we um say this is run undefined Behavior there's a caveat about the iterators of filters and that says modification to an inator of a filter view is permitted but results in undefined Behavior if the resulting value does no longer satisfy the filter predicate what so this code is undefined Behavior you writing a computer game you want to iterate about over all the monsters that are dead and you want to resurrect them that is undefined Behavior because resurrecting the monsters is breaking the predicate we have intentionally designed the filter View in a way that one of the major use cases we use a filter for which is fix the broken elements has undefined Behavior by the way that was not necessary there's no need to catch but uh that's something we discussed behind the scenes that's a defined behavior and I want to pointed out that even in views even in ranges there are still iterators used a lot and sometimes they have crazy behavior intentional the group who standardized this Library does not think this is a bug that's a feature because we make multi past iterations fast don't do that that's a recommendation I think you can hear that I'm not happy with that yes one question here if you do a single pass is that behavior or it just if you do a single pass it works that's the fun part it works yes but it's undefined Behavior there's the statement so do it and hope the best that nobody comes up with a very interesting way to implement this okay but don't reuse the view use it always at HW the fil that's a that's a benefit okay we are at the end iterators it's a key a key element for the success of C++ we use them everywhere where we have more than one element it's a gluc code between ranges and algorithms and that's still true even with ranges in views it's a pure abstraction everything that behaves like an iterator is an iterator different categories are provided so different iterators have have different abilities usually in general iterators do not know their ranges that for that reason they don't know where the end is they cannot insert or remove elements use iterators with care because they have reference semantics they refer to something that something still has to exist and if you compare to iterators they should refer to the same range and iterators of C++ 2x filters and other views cache which has some interesting consequences yeah I know my time is over do we have time for one question one is there any question so otherwise it might be completely compelling yes hi a microphone yeah otherwise I would have repeated the question but thanks why did they remove the ability to derive from stood iterator and make us declare everything to make a custom iterator so what what the the person asking is is uh saying indirectly is there was a base class called stator well this base class was only syntactic sugar to make um the definition a little bit easier it was never required to have it because all we requires Behavior not a specific base class then there were some issues with that so that's why we did that no big deal good that was a last question I hope you learned something about iterators I hope you're not too frustrated about C+ plus 20 a lot of good things are there and yeah it's challenging and it's still challenging to use C++ let's hope the best [Applause] enjoy
Info
Channel: CppCon
Views: 23,162
Rating: undefined out of 5
Keywords: Iterators, Iterators in C++, iterators in cpp, back to basics, back to basics c++, back to basics cppcon, Nicolai Josuttis, nico josuttis, iteration, ranges, views, STL, back to basics cpp, Standard Template Library, ranges c++, c++20 views, c++20 ranges, c++ 20, programming, software, c++, cpp, cppcon, c++con, cpp con, c++ con, cppcon 2023, in cpp, in c++, 2023, talks, tutorial, code, c plus plus, design of iterators, design, basics of iterators, guide to iterators, c++ iteration, api
Id: 26aW6aBVpk0
Channel Id: undefined
Length: 62min 22sec (3742 seconds)
Published: Tue Jan 02 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.