Forumite Members › General Topics › Tech › Makers & Builders › Programming/Code tips › C++ Programming
- This topic has 258 replies, 5 voices, and was last updated 2 years, 12 months ago by
Wheels-Of-Fire.
-
AuthorPosts
-
January 4, 2021 at 10:04 pm #65259
I just found something that Visual Studio Intellisense doesn’t spot.
If I create a vector like so :
vector<int> v1 {1, 2, 3};
Then I get a vector with three int elements, as is normal. If I then create a pointer to the 2nd element (unwise ) like this:
Int* ptrv1 = &v1[1];
Thats fine too. Now I can dereference ptrv1 and print its value, in this case 2, as follows:
cout << *ptrv1;
Works fine, but if I do this:
v1.push_back(4);
And then try to output the value of ptrv1 again, the program will compile but terminate with a memory access violation exception.
The reason is I expanded the vector so all its indexes moved to a bigger memory block, making my pointer invalid.
January 5, 2021 at 4:52 pm #65396Ooh, I have been promoted to Editor status on Stack Overflow.
Please do not join the unfriendly barstewards on Stack Overflow who expect noobs to either know that a question has been asked before or fail to make allowance for the question being badly framed due to the questioner’s knowledge level being insufficient.
I have given up using Stack for Python because the Python purists fail to recognise the (many) shortcomings of the Python syntax. (the biggest for C/C++/Delphi users being the use of white space separators.)
January 5, 2021 at 9:17 pm #65408They are much worse than unfriendly, they are mostly dim and self important too :negative:
I haven’t asked a question on there for ages but I sometimes answer them. For which I get abuse about not following the house style and threats of having my answer removed, followed by a load of up votes from people who were helped by my answer :mail:
Really, a lot of them just seem to like the look of their name in print. Its not so bad on the C++ tag but some of the replies on the Java tag are pure drivel.
January 7, 2021 at 3:34 pm #65523I have been looking again at C++ Container iterators and I think I finally get it. Here is my understanding of them.
Every C++ library container class (vector, string, etc) provides a special type of reference called an iterator. Every container class has the member functions .begin() and .end() that can be used to obtain an iterator to the first and one past the last element of a container like so, for vector v:
auto b = v.begin(), e = v.end();
I used “auto” above because the type of a and b is “iterator” and each container defines its own iterator type within its own namespace and its not often important to know what the exact type is. Iterators are objects (like pointers) so if you really must create an empty iterator then you can create one called “it” like this:
vector<int> :: iterator it;
Like with pointers it is possible to dereference an iterator to obtain the object it references.
The main use for iterators is to iterate over the elements of a container (Not really a surprise !) so they support ++ and –. If you inc or dec an iterator you do NOT inc/dec its value, you inc/dec the container index it refers to.
January 7, 2021 at 3:53 pm #65525I meant the type of b and e of course :wacko:
January 7, 2021 at 6:37 pm #65535Iterators sound very much like linked lists in C. Is there a special class of iterators that acts like a blockchain (i.e. the iterator is hashed or otherwise encrypted)?
January 7, 2021 at 8:08 pm #65539The container iterators do indeed provide similar functionality to a doubly linked list but the way things are organised in memory are different. The elements of a doubly linked list contain their data and pointers to the location of the previous and next member of the list (as you no doubt know) so the members of the list can be anywhere in memory, the compiler only needs to keep track of the first element to find all the rest.
The thing with a container is that it does NOT store its data in the index list (except for C++ style strings which DO. Storing an index pointer to a single byte would be silly :wacko: ). The indexes of a container just point at the data they represent, they are strictly “vectors” to the data rather than pointers but the idea is the same. The upshot is that the data can be anywhere in memory
Container indexes are always the size of a vector, no matter what the size of the data type, and they are always stored contiguously in memory so there is no need for them to hold the address of the previous or next index, they are always previous or next in memory. Again the compiler only needs to keep track of the first element to find the rest.
The indexes of a container MUST move to a bigger memory block if a container is expanded because the indexes must remain contiguous and you cant just tack a new index on the end, who knows what that memory may belong to ?
The main point of a container is that it is quick to expand because only the indexes have to move, the data stays put. If you want to stop your indexes from moving, and you know the maximum size of your container in advance, you can use the .reserve(n) member function that C++ container classes provide. The .reserve(n) function reserves a set number of indexes but it does not set a limit so your indexes will only stay put as long as your container doesn’t expand past that number.
As for hashed iterators ? I don’t know yet, my book covers them in more detail in about 400 pages time :unsure:
January 8, 2021 at 3:02 pm #65580I have just read something else about iterators and some interesting stuff about the built in array type. I am not sure if the following is how it always was under C but this is what happens with C++.
The first thing is that the compiler usually treats the name of an array as a pointer to the first element of the array so it is of type pointer rather than an array type so I can do the following:
string nums [] = {“one”, “two”, “three”};
string *ptr = nums;
Notice I did not need the “&”, address of, operator in front of nums because nums is already a pointer and it refers to the value “one”.
The next thing of note is that pointers to array elements are treated like iterators so if I do this:
++ptr1;
ptr1 now refers to the second element in the array and the value “two”.
The third thing of note is that arrays are built in types rather than classes so they don’t have the .begin() and .end() functions that C++ containers do. To get around this potential problem, C++11 provides a new class header in the standard library called “iterator” and it contains the .begin() and .end() functions for built in arrays. I can use those functions to get pointers to the first and last elements of an array as follows:
string *beg = begin(ptr1);
string *end = end(ptr1);
Those pointers can now be used in the same way as an iterator would be to access members of the array and iterator arithmetic applies.
January 8, 2021 at 3:06 pm #65582.end() gives you a pointer to one past the last element of an array, as with containers. Sorry :wacko:
January 8, 2021 at 3:17 pm #65584And all the pointers in the example are called ptr1, I missed the one off the first one.
January 8, 2021 at 4:04 pm #65590C lacks the beginning and end functions otherwise it is very similar with pointers instead of iterators. The one huge difference I guess is that you have to be extremely careful with allocating memory and garbage collection in C.
As a rule of thumb, C is very similar to C++ except it lacks all the things that should stop you being stupid (or evil :whistle: ).
January 8, 2021 at 5:28 pm #65602Yes, if you use the features of C++ as intended you can be extremely LAZY and still be safe . But if you CHOOSE to be stupid… 🙂
January 10, 2021 at 2:31 am #65699#include<iostream>
#include<iterator>using std::cout;
using std::string;int main()
{
string nums[] = { “one”, “two”, “three”, “four” }; // List initialise an arrystring* ptr1 = nums;
string* beg1 = begin(nums);
string* end1 = end(nums);–end1;
cout << *nums << ” ” << *beg1 << ” ” << *end1; // Prints one one four
}
The above code works as expected but I removed the “using namespace std” statement I was using before and replaced it with explicit “using” statements (As I really should). I was just wondering why I don’t need a using for begin() and end() ? You can see I included <iterator> but that’s not usually enough.
January 10, 2021 at 2:53 am #65702Works as expected except that I meant to output “*ptr1” not “*nums”. Good job its only an example.
January 10, 2021 at 9:56 am #65739“I was just wondering why I don’t need a using for begin() and end() ?”
I’d guess that it is explicitly declared in the ‘iterator’ definition, somewhere in the standard library, along with the definition for ‘string’.
C++ has doubtless moved on a lot since I last dabbled with it, but back in those days C++ was written in C as it was just an extension of C. Nowadays I believe the C++ compiler is somehow recursively written in C++!
January 10, 2021 at 10:38 am #65744Well thats the thing, I DO need a “using” for “string” otherwise the compiler sees it as a local variable. On the other hand I had to call my pointer “end1” because when I tried to call it “end” the compiler complained about a bad call to end() :wacko:
Some parts of the C++ standard library are indeed written in C++ but some parts of the C library were also written in C !
January 10, 2021 at 10:56 am #65748I was also reminded that end() returns a pointer to one past the end of an array because when I forgot the – – end1; statement (the prefix version of – – that always occurs before any other evaluation in a statement that uses it) the program compiled but threw a memory access exception. Not totally safe after all then 🙁
January 11, 2021 at 10:15 pm #65855I have come across a new annoyance, relating to the online code that is provided with some books.
I have already encountered code that uses new C++ features but tries to stay compatible with older compilers by using pre-processor directives, using an #ifdef to check for the existence of pre-processor variables is common, providing a custom function if the variable doesn’t exist. The problem seems to occur if the variable DOES exist but a newer compiler implements the function in a different way from the custom function.
The new annoyance is code that uses features from a newly released version of the C++ standard but that haven’t been implemented in any compiler at the time the book was published, they use the same trick as above but they can’t know for sure what variable name a newer compiler will use to represent a feature.
I just had the above problem and it took 30min to figure out. In my experience its easier to find a problem with missing features than it is to work out what they did to try to prevent a problem !
January 12, 2021 at 10:06 am #65887Imo you learn a lot more by fixing something than you do by trying to learn it.
January 12, 2021 at 6:41 pm #65937You’re not wrong there Ed, I wouldn’t have looked at the pre-processor yet, if I hadn’t had a problem with a program that used it. On the other hand, I didn’t really WANT to be looking at the pre-processor yet !
I am now going back to looking at classes, starting with the implied “this” parameter that class member functions use. Wish me luck :scratch:
-
AuthorPosts
- You must be logged in to reply to this topic.
