vector<vector<string> > vvs;
vector<string> vs;
vs.push_back("r1-c1");
vs.push_back("r1-c2");
vs.push_back("r1-c3");
vvs.push_back(vs);
for (vector<vector<string> >::iterator vvsi = vvs.begin(); vvsi != vvs.end(); vvsi++) {
vector<string> vec_str = *vvsi;
for (vector<string>::iterator vsi = vec_str.begin(); vsi != vec_str.end(); vsi++) {
cout << *vsi << ", ";
}
cout << "\n";
}
In the above C++ code, to avoid the copy of vector(vector vec_str = *vvsi) i tried the below code
vector<string> *vec_str = vvsi.base(); //Working. which (returns a const pointer&)
vector<string> *vec_str = &(*vvsi); //Working. Assigning the address
But
vector<string> *vec_str = vvsi; //Error. Not able to assign
Error
(build error : cannot convert 'std::vector<std::vector<std::basic_string<char> > >::iterator to 'std::vector<std::basic_string<char> >*' in initialization)
In a case of integer
int a=10;
int *b = &a; //working. Assigning address
int *c = &(*b); //working. Assigning address
int *d = b; //working. Assigning address
*c=11;
std::cout << a<<"\n";
*d=12;
std::cout << a<<"\n";
In the case of vector, why the build error when assigning (can't able to understand from the C++ iterator documentation)?
An iterator is not a pointer. It's interface was made to be used as a pointer, but it certainly is not a pointer.
However, if you simply want to iterate through the elements of each vector in the parent vector, there is no need to assign it to a temporary vector or to a pointer, the iterator itself is good enough:
for (vector<vector<string> >::iterator vvsi = vvs.begin(); vvsi != vvs.end(); ++vvsi) {
for (vector<string>::iterator vsi = vvsi->begin(); vsi != vvsi->end(); ++vsi) {
cout << *vsi << ", ";
}
cout << "\n";
}
Also, since you put c++11 as a tag in your question, I assume you might be interested in a more modern expression:
for(auto& vst : vvs){
for(auto& st : vst){
cout << st << ", ";
}
cout << endl;
}
You're trying to assign the value of an iterator to a pointer. That the iterator points to the same type as the pointer is irrelevant, since RandomAccessIterators, which are the iterator type of std::vector, are not implicitly convertible to pointers.
If you're using c++11, there are simpler ways to go about iterating over a vector of a vector even than #A Hernandez's solution (or any container of containers at that), using the range-for syntax available in c++14:
for(auto &&stringVec : vvs){
for(auto &&str : stringVec){
cout << str << ", ";
}
}
cout << '\n';
The && here allows binding to temporary containers as well as existing ones, so you can use this syntax with both existing container containers and container containers returned from a function without storing them.
Related
I do not know, why does it output 1024?
vector<int> default_container = { 1,2,3,4,5,6,7,78,8,1024 };
cout << *default_container.end() << endl; // 0
default_container.pop_back();
for (auto it : default_container)
{
cout << it << ",";
}
cout << endl;
cout << *default_container.end() << endl; // 1024 why?why?why?why?
cout << *--default_container.end() << endl; // 8
Your program has Undefined behavior!
You are de-referencing the end iterator, at the lines
cout << *default_container.end() << endl;
...
cout << *default_container.end() << endl;
which gives you undefined behavior. Form cppreference.com the std::vector::end, std::vector::cend
Returns an iterator to the element following the last element of the vector.
This element acts as a placeholder; attempting to access it results in undefined behavior.
Means, anything can be happened; therefore you shouldn't be relaying on its result and should not be doing it!
That being said, it looks like that you want to access the last element in the vector. If that the case, for a non-empty vector you have multiple other (safe) choices:
Using std::vector::back
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << default_container.back();
Using std::prev
#include <iterator>
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::prev(default_container.end());
Using reverse iterator std::rbegin
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::rbegin(default_container);
As a side note, see: Why is "using namespace std;" considered bad practice?
The previous answer says it all.
In other words you're not supposed to use end() for anything else then comparing an iterator to.
Eg.
for (auto it = container.begin(); it < container.end(); ++it)
Also note that your line for (auto it : default_container)
isn't creating an iterator but literally an int.
// foreach value in container
for(int value : default_container)
{
cout << value;
}
note that if you're not planning to change the values you're iterating over you can use this :
for(const auto value : default_container) {}
or if your containter contains objects (instance of classes)
for(const auto& object : container) {}
It has been a while that I've written code in C/C++, and I've already found an alternative solution to my problem, but I would like to know why the original code doesn't work.
I have a test class which basically only stores a string.
class test {
private:
std::string name;
public:
test(std::string name) : name(name) {};
std::string get_name() { return name; }
};
In main I have a vector which I at one point fill with test objects. The code below simulates irregular usage of the vector vect.
int main(void) {
std::vector<test *> vect;
std::vector<test *>::iterator i;
//* Comment this for a working example
std::cout << "Searching empty vector" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
} // */
vect.push_back(new test("test 1"));
vect.push_back(new test("test 2"));
vect.push_back(new test("test 3"));
std::cout << "All:" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i != vect.end()) {
std::cout << "Erase " << (*i)->get_name() << std::endl;
vect.erase(i);
delete *i;
}
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
}
std::cout << "Left:" << std::endl;
for (i = vect.begin(); i!=vect.end(); ++i) {
std::cout << (*i)->get_name() << std::endl;
delete *i;
}
vect.clear();
return 0;
}
Because searching in the vector for a test object happens multiple times, I've created the function _is_in_vector that searches a test object and returns the iterator to it.
static std::vector<test *>::iterator * _is_in_vector(std::vector<test *> &vect, std::string find) {
std::string identity = find;
static std::vector<test *>::iterator i = vect.begin();
std::cout << "Vect size: " << vect.size() << std::endl;
for (i; i != vect.end(); ++i) {
std::string tmp = (*i)->get_name(); /* Segmentation fault after filling vector*/
if (0 == identity.compare(tmp)) break;
}
return &i;
}
The problem is that the code above works when I comment out the Searching empty vector part in main. Once the vector is filled with test objects, I call _is_in_vector a second time. The vector in this function does have three entries, but (*i) all point to NULL.
Output:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Segmentation fault
Expected output:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Erase test 3
Vect size: 2
Nothing found
Left:
test 1
test 2
First of all it is unclear why you need to store test objects by pointer but not by value. If you do need it use smart pointer.
As for your problem, why do you return pointer to an iterator? This is the root cause of your problem - to make &i legal to return you made it static, but static local variables initialized only once and do not change value btw calls - so after first call it pointed to an element in the vector, but after that you added elements and invalidated all iterators including static i hense the segmentation fault. So fix is simple - return iterator by value and make i non static but regular, it is light and it is totally fine to do so.
PS Identifiers starting with _ are illegal in global context, details can be found here What are the rules about using an underscore in a C++ identifier?
So your function actually should look like this:
static std::vector<test *>::iterator is_in_vector( std::vector<test *> &vect, const std::string &find)
{
return std::find_if( vect.begin(), vect.end(), [find]( test *p ) {
return p->get_name() == find;
} );
}
assuming the vector should never hold nullptr, if it is the case or to play safe change condition to:
return p && p->get_name() == find;
I'm trying to print elements of a vector of list pair in a hash-table program in C++.
If I use the C++11 auto it's working but if i use a iterator
for (vector<int>::iterator i = arr_Hash[i].begin(); i != arr_Hash[i].end(); ++i)
//for (auto index = arr_Hash[i].begin(); index != arr_Hash[i].end(); index++)
{
cout << i->second;
cout << " ";
}
Error list: https://i.imgur.com/rDejBGG.png
How can I use the iterator here?
vector<int>::iterator i = arr_Hash[i].begin()
You're reusing the variable i here. Call it something else.
std::cout << i->second;
i is a std::vector<int>::iterator. Dereferencing it gives you an int&, which has no second member. You probably just want std::cout << *i;
The iterator for arr_Hash[i] needs to be on the same type as the vector.
Namely, if the type of arr_Hash[i] is vector<pair<int,int>> then it's iterator needs to be vector<pair<int,int>>::iterator.
Howerver, you should Prefer a range-for-statement to a for-statement when there is a choice.
for (auto& e : arr_Hash[i])
cout << i->second << " ";
How do I iterate over this C++ vector?
vector<string> features = {"X1", "X2", "X3", "X4"};
Try this:
for(vector<string>::const_iterator i = features.begin(); i != features.end(); ++i) {
// process i
cout << *i << " "; // this will print all the contents of *features*
}
If you are using C++11, then this is legal too:
for(auto i : features) {
// process i
cout << i << " "; // this will print all the contents of *features*
}
C++11, which you are using if this compiles, allows the following:
for (string& feature : features) {
// do something with `feature`
}
This is the range-based for loop.
If you don’t want to mutate the feature, you can also declare it as string const& (or just string, but that will cause an unnecessary copy).
I'm trying to get a simple bit of code to work. I have a function called 'get_object_radius' which searches an area for instances of 'Creature', and pushes their pointers to a vector, then returns the vector.
I then want to cycle through them all and display their names from outside the function. I'm pretty sure I'm adding them to the vector correctly, but I'm not cycling through the vector of pointers correctly, am I?
Here's the relevant code snippet (that doesn't work):
//'get_object_radius' returns a vector of all 'Creatures' within a radius
vector<Creature*> region = get_object_radius(xpos,ypos,radius);
//I want to go through the retrieved vector and displays all the 'Creature' names
for (vector<Creature*>::iterator i = region.begin(); i != region.end(); ++i) {
cout<< region[i]->name << endl;
}
Any ideas what I'm doing wrong?
http://www.cplusplus.com/reference/stl/vector/begin/
You dereference the iterator to get to the underlying object.
cout << (*i)->name << endl;
Try:
//I want to go through the retrieved vector and displays all the 'Creature' names
for (vector<Creature*>::iterator i = region.begin(); i != region.end(); ++i) {
cout << (*i)->name << endl;
}
You need to dereference the iterator (using the * operator), which then gives you Creature* pointer.
To get the element iterator is pointing at, you dereference it (like a pointer, but iterators are not necessarily pointers). So your code should look like this:
// auto is C++11 feature
for (auto it = region.begin(); it != region.end(); ++it) {
Creature *p = *it;
std::cout << p->name << "\n";
}
In C++11 you also get range for, which hides iterators from your view:
for (Creature *p : region) {
std::cout << p->name << "\n";
}