How to properly iterate over QT's STL style vector - c++

I am trying to iterate over a vector.
The vector memory is initialized to hold 10 elements max.
Now I assigned first 3 elements and try to print them using STL style iterator in QT.
#include <QDebug>
int main() {
QVector<int> vv(10);
vv[0] = 1;
vv[1] = 2;
vv[2] = 3;
QVector<int>::iterator itt;
for (itt = vv.begin(); itt != vv.end(); ++itt) {
qDebug() << vv.at(*itt);
}
}
the output is weird:
It's not 1 2 3
instead its 2 3 0 1 1 1 1 1 1 1
Why is this happening ? Can you someone explain this please.

As #NathanOliver pointed out you have two problems:
*itt already is the element of the vector, so it should just be qDebug() << *itt;.
If you create a vector of a certain size for each vector index a default element of the type the vector holds is created. That is also the reason why you can't use container classes like QVector for types without a default constructor. In your case the vector is filled with 1s on creation because 1 is the default value of an int. You then just override the first 3 values.
I have some further concerns regarding your code:
If you expect your vector to only hold as much values as you add, why even provide a length of the vector? QVector is perfectly capable of managing its storage itself. You just use QVector::append or QVector::operator<< to add values and your vector has exactly as many values as you added.
Why use STL style iterators in this case anyway? QVectorIterator provides such convenient methods to iterate over a vector. They also make the code much more readable.
If I were you I would have written the code as follows:
#include <QVector>
#include <QDebug>
int main() {
QVector<int> numbers = QVector<int>() << 1 << 2 << 3;
QVectorIterator<int> itNumbers(numbers);
while (itNumbers.hasNext()) {
qDebug() << itNumbers.next();
}
}

Related

Vector of set insert elements

I'm trying to write a function which will return vector of set type string which represent members of teams.
A group of names should be classified into teams for a game. Teams should be the same size, but this is not always possible unless n is exactly divisible by k. Therefore, they decided that the first mode (n, k) teams have n / k + 1 members, and the remaining teams have n / k members.
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <list>
typedef std::vector<std::set<std::string>>vek;
vek Distribution(std::vector<std::string>names, int k) {
int n = names.size();
vek teams(k);
int number_of_first = n % k;
int number_of_members_first = n / k + 1;
int number_of_members_remaining = n / k;
int l = 0;
int j = 0;
for (int i = 1; i <= k; i++) {
if (i <= number_of_first) {
int number_of_members_in_team = 0;
while (number_of_members_in_team < number_of_members_first) {
teams[l].insert(names[j]);
number_of_members_in_team++;
j++;
}
}
else {
int number_of_members_in_team = 0;
while (number_of_members_in_team < number_of_members_remaining) {
teams[l].insert(names[j]);
number_of_members_in_team++;
j++;
}
}
l++;
}
return teams;
}
int main ()
{
for (auto i : Distribution({"Damir", "Ana", "Muhamed", "Marko", "Ivan",
"Mirsad", "Nikolina", "Alen", "Jasmina", "Merima"
}, 3)) {
for (auto j : i)
std::cout << j << " ";
std::cout << std::endl;
}
return 0;
}
OUTPUT should be:
Damir Ana Muhamed Marko
Ivan Mirsad Nikolina
Alen Jasmina Merima
MY OUTPUT:
Ana Damir Marko Muhamed
Ivan Mirsad Nikolina
Alen Jasmina Merima
Could you explain me why names are not printed in the right order?
teams being a std::vector<...> supports random access via an index.
auto & team_i = teams[i]; (0 <= i < teams.size()), will give you an element of the vector. team_i is a reference to type std::set<std::list<std::string>>.
As a std::set<...> does not support random access via an index, you will need to access the elements via iterators (begin(), end() etc.), e.g.: auto set_it = team_i.begin();. *set_it will be of type std::list<std::string>.
Since std::list<...> also does not support random access via an index, again you will need to access it via iterators, e.g.: auto list_it = set_it->begin();. *list_it will be of type std::string.
This way it is possible to access every set in the vector, every list in each set, and every string in each list (after you have added them to the data structure).
However - using iterators with std::set and std::list is not as convenient as using indexed random access with std::vector. std::vector has additional benefits (simple and efficient implementation, continous memory block).
If you use std::vectors instead of std::set and std::list, vek will be defined as:
typedef std::vector<std::vector<std::vector<std::string>>> vek;
std::list being a linked list offers some benefits (like being able to add an element in O(1)). std::set guarentees that each value is present once.
But if you don't really need these features, you could make you code simpler (and often more efficient) if you use only std::vectors as your containers.
Note: if every set will ever contain only 1 list (of strings) you can consider to get rid of 1 level of the hirarchy, I.e. store the lists (or vectors as I suggested) directly as elements of the top-level vector.
UPDATE:
Since the question was changed, here's a short update:
In my answer above, ignore all the mentions of the std::list. So when you iterate on the set::set the elements are already std::strings.
The reason the names are not in the order you expect:
std::set keeps the elements sorted, and when you iterate it you will get the elements by that sorting order. See the answer here: Is the std::set iteration order always ascending according to the C++ specification?. Your set contains std::strings and the default sort order for them is alphabetically.
Using std::vector instead of std::set like I proposed above, will get you the result you wanted (std::vector is not sorted automatically).
If you want to try using only std::vector:
Change vek to:
typedef std::vector<std::vector<std::string>>vek;
And replace the usage of insert (to add an element to the set) with push_back to do the same for a vector.

Should you always initialise C++ std::vectors?

I am coming from a C background where, as common practice, variables are always initialized to prevent undefined behavior. You normally, don't have any meaningful value when declaring the variables, you set the variables to 0 or {}.
I am new to C++ and I am about to code an app, which C++ classes will contain std::vectors with very long sizes... so I am just wondering if the same principles apply to std::vectors or not... and save a few loops of computational requirements
Thanks!
You will not be able to create a Vector, which is not initialized. The default constructor constructs an empty container with a default-constructed allocator.
Here are some examples on how to initialise a Vector if you already know its content or size.
// Will be an initialised empty Vector
std::vector<std::string> words;
// c++11 initializer list syntax:
std::vector<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
std::cout << "words1: " << words1 << '\n';
// words2 == words1
std::vector<std::string> words2(words1.begin(), words1.end());
std::cout << "words2: " << words2 << '\n';
// words3 == words1
std::vector<std::string> words3(words1);
std::cout << "words3: " << words3 << '\n';
// words4 is {"Mo", "Mo", "Mo", "Mo", "Mo"}
std::vector<std::string> words4(5, "Mo");
std::cout << "words4: " << words4 << '\n';
when you create a vector it gets default initialized, so it's up to you if you want to initialize it with user default values or not.
You will always get an empty vector container if you don't initialize it.
You have different ways to initialize vector to defaults like provided by #nils
but the important thing to note is std::vector encapsulates dynamic size arrays so the memory allocated to them is generally more than a static array as memory is allocated for the future growth of vector also.
Refer std::vector for more details .
and the capacity() function to understand the memory allocation to vectors .
std::vector<int> vc1(5); // number of elements
// 0 0 0 0 0
std::vector<int> vc2(5, 0); // number of elements, value of each element
// 0 0 0 0 0
That two vectors, vc1 and vc2, are same way to create new vector.

Why iterator is not dereferenced as an lvalue

Apologies if my question does not contain all relevant info. Please comment and I will amend accordingly.
I use CLion on Win7 with MinGW and gcc
I have been experimenting with circular buffers and came across boost::circular_buffer, but for the size of my project I want to use circular buffer by Pete Goodlife, which seems like a solid implementation in just one .hpp.
Note: I am aware of how to reduce boost dependecies thanks to Boost dependencies and bcp.
However, the following example with Pete's implementation does not behave as expected, i.e. the result to std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin()); comes out empty. I would like to understand why and possibly correct its behaviour.
Follows a MWE:
#include "circular.h"
#include <iostream>
#include <algorithm>
typedef circular_buffer<int> cbuf_type;
void print_cbuf_contents(cbuf_type &cbuf){
std::cout << "Printing cbuf size("
<<cbuf.size()<<"/"<<cbuf.capacity()<<") contents...\n";
for (size_t n = 0; n < cbuf.size(); ++n)
std::cout << " " << n << ": " << cbuf[n] << "\n";
if (!cbuf.empty()) {
std::cout << " front()=" << cbuf.front()
<< ", back()=" << cbuf.back() << "\n";
} else {
std::cout << " empty\n";
}
}
int main()
{
cbuf_type cbuf(5);
for (int n = 0; n < 3; ++n) cbuf.push_back(n);
print_cbuf_contents(cbuf);
cbuf_type df(5);
std::adjacent_difference(cbuf.begin(),cbuf.end(),df.begin());
print_cbuf_contents(df);
}
Which prints the following:
Printing cbuf size(3/5) contents...
0: 0
1: 1
2: 2
front()=0, back()=2
Printing cbuf size(0/5) contents...
empty
Unfortunately, being new to c++ I can’t figure out why the df.begin() iterator is not dereferenced as an lvalue.
I supsect the culprit is (or don't completely uderstand) the member call of the circular_buffer_iterator on line 72 in Pete's circular.h:
elem_type &operator*() { return (*buf_)[pos_]; }
Any help is very much appreciated.
The iterator you pass as the output iterator is dereferenced and treated as an lvalue, and most probably the data you expect is actually stored in the circular buffer's buffer.
The problem is, that apart from the actual storage buffer, most containers also contain some internal book-keeping state that has to be maintained. (for instance: how many elements is in the buffer, how much frees space is left etc).
Dereferencing and incrementing the container doesn't update the internal state, so the container does not "know" that new data has been added.
Consider the following code:
std::vector<int> v;
v.reserve(3);
auto i = v.begin();
*(i++) = 1; // this simply writes to memory
*(i++) = 2; // but doesn't update the internal
*(i++) = 3; // state of the vector
assert(v.size() == 0); // so the vector still "thinks" it's empty
Using push_back would work as expected:
std::vector<int> v;
v.reserve(3);
v.push_back(1); // adds to the storage AND updates internal state
v.push_back(2);
v.push_back(3);
assert(v.size() == 3); // so the vector "knows" it has 3 elements
In your case, you should use std::back_inserter, an iterator that calls "push_back" on a container every time it is dereferenced:
std::adjacent_difference(
cbuf.begin(), cbuf.end(),
std::back_inserter(df));
std::adjacent_difference writes to the result iterator. In your case, that result iterator points into df, which has a size of 0 and a capacity of 5. Those writes will be into the reserved memory of df, but will not change the size of the container, so size will still be 0, and the first 3 ints of the reserved container space will have your difference. In order to see the results, the container being written into must already have data stored in the slots being written to.
So to see the results you must put data into the circular buffer before the difference, then resize the container to the appropriate size (based in the iterator returned by adjacent_difference.

How do I access the elements of a vector correctly?

int main() {
vector <int> multiples(1);
cout << multiples[0];
}
This returns 0 when I want it to be 1. This happens when I initialize the vector with one element, I can access the second element, however:
int main() {
vector <int> multiples(1, 4);
cout << multiples[1]; // 4
}
Moreover, when I try to access elements in the vector that do not exist, I get the value of the rightmost element (in this case, 4). But I cannot seem to get the first element however. Can anyone explain why?
This
vector <int> multiples(1);
creates a vector of int with size 1. The single element is value initialized, which for ìnt means zero initialized. So you get a vector with one entry, with value 0. And this one
vector <int> multiples(1, 4);
creates a vector of size 1, this time with value4. If you try to access multiplies[1] you are going beyond the bounds of your size-1 vector, thereby invoking undefined behaviour. It you want to initialize a vector with two elements of values 1 and 4, in C++11 you can do this:
vector <int> multiples{1, 4};
int main() {
vector <int> multiples(1);
cout << multiples[0];
}
http://cplusplus.com/reference/stl/vector/vector/
creates vector with 1 int element, initialized by default (i.e. int() == 0).
vector <int> multiples(1, 4);
creates vector with 1 int element initialized by 4.
cout << multiples[1]; // 4
it's incorrect, since there only one element in vector.
Take a look at this code. You should see the problem. You are not initializing the vector in the way that you expected.
int main()
{
vector <int> multiples(2); // create a vector of size two with default value of 0.
multiples[0] = 10; // set element at index 0 = 10
multiples[1] = 20; // set element at index 0 = 10
cout << multiples[0]; // 10
cout << multiples[1]; // 20
}
Actually, you dont need to specify the size of vector.
You can add elements (objects to be specific) as and when you require, that is the main advantage and use of vectors. Adding an element to vector can be easily done by:
multiples.push_back(1);
multiples.push_back(4);
Hope it helps.

the value of iterator

i created a map.
i want to print the index of the key to a file using the itr in the map.
this is what i mean:
map <string,int> VendorList;
VendorList[abc] = 0;
VendorList[mazda] = 111;
VendorList[ford] = 222;
VendorList[zoo] = 444;
map <string,int>::iterator itr=VendorList.find("ford");
fstream textfile;
textfile << itr;
if i put in the find line abc i wish the program to cout 1.
if i put in the find line mazda i wish the program to cout 2.
if i put in the find line ford i wish the program to cout 3.
if i put in the find line zoo i wish the program to cout 4.
how do i do that?
the compiler is shouting on the line:
textfile << itr;
it gives this error:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::_Tree<_Traits>::iterator' (or there is no acceptable conversion)
Your program has many bugs. Frankly speaking I am not sure about your requirement.
But anyways try this :
map <string,int> VendorList;
VendorList["abc"] = 1;
VendorList["mazda"] = 2;
VendorList["ford"] = 3;
VendorList["zoo"] = 4;
map <string,int>::iterator itr=VendorList.find("ford");
cout<<(itr->second);// this will print 3
EDIT :
Also as somebody has suggested to use vector of pairs,I think he is right. Try something like this.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
typedef vector<pair<string,int> > Vm;
Vm V;
V.push_back(make_pair("abc",0));
V.push_back(make_pair("mazda",111));
V.push_back(make_pair("ford",222));
V.push_back(make_pair("zoo",444));
for(size_t i=0;i!=V.size();++i)
if(V[i].first=="ford")
cout<<(i+1);
}
Modify the above program as per requirement.
Hope that helps.
In map, the elements aren't stored in the order of insertion, so you have to hold the "order" data yourself.
I would suggest you to consider using a vector of pairs instead of a map. Vector does store the elements in the order of insertion, and its iterator is Random-Access so you will be able to check the position using the operator-.
vector <pair<string, int> >::iterator itr;
// itr = the needed element
cout << itr - VendorList.begin();
As such, the concept of 'index' doesn't really fit with Maps.
Maps are just key-value pairs where you store a value (say, '111') and access it using a key (say 'mazda'). In this way you don't really need an index in order to access '111', you can just use the key 'mazda'.
If you do want your application to be index based however, consider using a different data structure like a Vector or a Linked List.