C++ STL Vector Iterator accessing members of an Object - c++

I think I've declared a Vector with an object correctly. But, I don't know how to access it's members when looping with Iterator.
In my code, the line --->> cout << " " << *Iter;
How do I print the contents of the members? Like *Iter.m_PackLine ???
Not sure if I used the correct terminology, but appreciate the help! Thanks
class CFileInfo
{
public:
std::string m_PackLine;
std::string m_FileDateTime;
int m_NumDownloads;
};
void main()
{
CFileInfo packInfo;
vector<CFileInfo, CFileInfo&> unsortedFiles;
vector<CFileInfo, CFileInfo&>::iterator Iter;
packInfo.m_PackLine = "Sample Line 1";
packInfo.m_FileDateTime = "06/22/2008 04:34";
packInfo.m_NumDownloads = 0;
unsortedFiles.push_back(packInfo);
packInfo.m_PackLine = "Sample Line 2";
packInfo.m_FileDateTime = "12/05/2007 14:54";
packInfo.m_NumDownloads = 1;
unsortedFiles.push_back(packInfo);
for (Iter = unsortedFiles.begin(); Iter != unsortedFiles.end(); Iter++ )
{
cout << " " << *Iter; // !!! THIS IS WHERE I GET STUMPED
// How do I output values of the object members?
}
} // end main

cout << " " << *Iter;
will only work if CFileInfo has an overloaded operator<< that can output your struct. You can output individual members of the struct instead like this:
cout << " " << Iter->m_PackLine;
Alternatively, the following is equivalent to that:
cout << " " << (*Iter).m_PackLine;
You have to put parentheses around *Iter, since the member-access operator binds thighter otherwise.
On a side-node, make your main function return int instead of void. making it return void is not valid in C++.
You declare the vector like this:
vector<CFileInfo, CFileInfo&> unsortedFiles;
The second argument to vector should be another thing. It's not needed for your code to give the vector a second argument at all. Just use this:
vector<CFileInfo> unsortedFiles;
Another thing i noticed is you increment the iterator using Iter++ (called postfix increment). For iterators, always prefer ++Iter, which is called prefix increment.

Use (*iter).member or iter->member.
You can also use temporaries:
CFileInfo &fileInfo = *iter;
cout << " " << fileInfo.myMember;
Also, for what you're doing, you'd probably want a const_iterator instead of an (mutable) iterator.
In addition, std::vector is a template accepting a typename and an allocator, not two typenames. You can use the default allocator by stripping the second template argument:
vector<CFileInfo> unsortedFiles;
vector<CFileInfo>::iterator Iter;
Some nit-picking:
main should return an int.
It'd probably be best to declare your iterator variable in the for statement.
It'd probably be faster in run-time performance to use the prefix ++ operator (++iter) instead of the postfix operator (iter++) in your for loop.
No need for your comment about main() ending.

This is the first problem I noticed:
std::vector is a template.
You have:
vector unsortedFiles;
you need something like:
vector<CFileInfo> unsortedFiles;
Now that I think about it, your template definition may have just gotten parsed out by the stackoverflow comment system.

iter->m_PackLine
or
(*iter).m_PackLine

First correct you'r vector declaration:
vector<CFileInfo > unsortedFiles;
Next you need to define an output operator for your class:
std::ostream& operator<<(std::ostream& str,CFileInfo const& data)
{
// Do something here
/* Potentailly you could do this
* But this requires that this function be a friend of the class
str << data.m_PackLine << ":"
<< data.m_FileDateTime << ":"
<< data.m_NumDownloads << ":";
* Or you could do this
data.print(str); // Make print a public const method.
*/
return str;
}
Usually you either make the output operator a friend of your class or provide a public print method that takes a stream. Either way you can then access the members and stream them manually to the output.
Once you have the output iterator defined you can change your loop to use the standard library versions:
std::for_each(unsortedFiles.begin()
unsortedFiles.end()
std::ostream_iterator<CFileInfo>(std::cout," ")
);

Thanks all, wish I could grant multiple points for the answers :)
litb also pointed out a problem I was having in my declaration of the vector. I removed the second argument in the vector declaration and it worked.
Stackoverflow parsed out some of my code, I'll be more careful in posting next time.

vector<CFileInfo, CFileInfo&> will not work at all. The second parameter to vector is the allocator the vector uses, and CFileInfo does not meet those requirements, nor does any reference type. I think you just want vector<CFileInfo>, the iterators and members will return CFileInfo& automatically.

Related

How can I iterate over a vector of functions and call each of them in C++?

I am trying to loop through an array of functions stored in a vector, and i want to call each of them by the iterator pointer object,
but something like this:
itr->funcs[i](5); // call the ith index function && pass int 5 as param
is not the solution i guess, what is the solution then ?
Below is my code, please check the last for loop in the code.
#include <iostream>
#include <string>
#include <vector>
// to be able to take other functions as arguments in a function
#include <functional>
using namespace std;
// receive other functions inside a function
// syntax: return_type function_name(std::function<return_type(parameter_lists)>func_name, parameter_lists)
double doMath(std::function<double(double)> someOtherFunction, double num){
return someOtherFunction(num);
}
double multBy2(double d){
// b'coz x is pointing to multBy2 the word 'someOtherFunction' in the
// above function behaves like an alias for this function 'multBy2'
return d * 2;
}
double multBy3(double d){
return d * 3;
}
int main (){
// dec && init
auto x = multBy2; // x pointing to multBy2 now
std::cout << "2 * 5.1 : " << x(5.1) << "\n";
std::cout << "multBy2 will be called: " << doMath(x, 6.1) << "\n";
std::cout << "multBy2 will be called, again: " << doMath(x, 6.1) << "\n";
// store different functions inside a vector
// you must use the same signature type functions
std::vector<function<double(double)>> funcs(2);
funcs[0] = multBy2; // multBy2 stored at the zeroth index
funcs[1] = multBy3; // multBy3 stored at the first index
// check
// funcs[0](10), pass value by index
std::cout << "2 * 10 = " << funcs[0](10) << "\n";
std::cout << "3 * 10 = " << funcs[1](10) << "\n";
// loop through them
for (auto itr = funcs.begin(); itr != funcs.end(); itr++){
// iterate through the functions
// itr->funcs[1](10); // I KNOW THIS IS WRONG, WHAT SHOULD I WRITE HERE?
}
return 0;
}
The variable itr is an iterator, which is basically a pointer, i.e. they both point to to an object. In this case the iterator is pointing to a function. You can get to the function by dereferencing itr (much like a pointer) with *itr. Then you can use this object like it's a function (because it is one):
for (auto itr = funcs.begin(); itr != funcs.end(); ++itr)
(*itr)(10); // like calling func[i](10)
Since it's an iterator, you might also want to use the -> operator, so that you can use the pointed at object directly. Unfortunately, if you tried to do what might seem like the obvious thing:
itr->(10); // error
the syntax of the language just doesn't allow it (parentheses can be tricky to figure out, even for a compiler). Fortunately, the language does have a way of allowing you to explicitly say what you mean, which is, "I just want to treat it like a function, so I can call it with ()". There is a function called the call operator which is spelled operator() that you can use. The syntax for that is:
for (auto itr = funcs.begin(); itr != funcs.end(); ++itr)
itr->operator()(10);
However, this syntax does seem to defeat the purpose of using the convenient -> operator in the first place.
However, I recommend that you use a range-for loop here (it's usually the better choice if you can use it). The syntax is much clearer at expressing the intent of the code:
for (auto &func : funcs) // for every function in funcs
func(10); // use the function
Here's a working demo.

Access pointer methods of pointer vector

I'm not really sure how to phrase the question exactly correctly, but I've declared two vectors
std::vector<enemy*> enemies;
std::vector<hit_area *> effects;
these work and are fine, however I pass them to a function with
handleGame(strd_maps[0], &gcam, &mainchar, currentKeyStates, &enemies, &effects)
which works and is fine, however in the function, when I try to access members or methods or enemies or effect
if(effects[d]->collide(enemies[i]->x, enemies[i]->y enemies[i]->w, enemies[i]->h))
I get the error "base operand of "->" has non-pointer type 'std::vector*'.
I can access the size of both enemies and effects, it's just accessing the methods that is giving problems
Normally you don't pass the address of a vector. Instead, you pass a reference:
void func(std::vector<enemy*> &enemies) {
std::cout << enemies.size() << '\n';
std::cout << enemies[i]->x << '\n';
}
// Call it like:
func(enemies);
If you pass the address of the vector, then you need to use some slightly wacky syntax, like:
std::cout << enemies->operator[](i).x << '\n';
So always use refrence in case of vectors

C++ overloading operator with/without defining a template

Problem: overload the default << operator for a vector<int> v variable, so that cout << v will print each element sequentially. Here I saw one option as proposed by Jason Iverson in the previous question
template<typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> t) {
s << "[";
for (std::size_t i = 0; i < t.size(); i++) {
s << t[i] << (i == t.size() - 1 ? "" : ",");
}
return s << "]" << std::endl;
}
Obviously this should work for any type of elements, however since I am only concerned with int, I simplified the function as
ostream& operator << (ostream &os, const vector<int> &v){
for (auto x: v){
os << " " << x;
}
return os;
}
It just works fine.
So my question is
As far as vector<int> v is concerned, what is the caveat of not using template?
Apart from being general-purpose, what is the advantage of Jason's solution?
Thanks!
Deeper thoughts:
The above question was poorly phrased, and thanks to the comments, I believe it makes sense to rephrase it.
Question: in C++, what is the cost of using template where a single-type function is enough?
Credits to #Marco A and #Walter, this question could be closed.
One of the main points of C++ is generic programming and templates are the way to do this.
The advantage is pretty obvious: you don't have to write the same/similar piece of code more than once and you don't have to debug/maintain similar pieces of code, but just one. (All of this falls in your category "general purpose", so there is no advantage beyond that).
There is actually some disadvantage, because a template is not a function (or class). A function (or class) will only be created from the template at compile time when it is actually used, whereas your (non-template) function may be pre-compiled. This has two implications: (1) more compiling and (2) that certain syntax errors in the code only turn up when the template is used with arguments for which they won't work. The template in your post, for example, won't compile if ostream << T has not been defined.

Expression must have a pointer type error

I have read the other similar posts, but still haven't found a way to solve my coding problem.
Here is the code:
void Foo(vector<Name> &obj){
vector<Name> *temp = 0;
temp = new vector<Name>;
if (!temp){
std::cout << "temp Allocation Error!" << std::endl;
exit(1);
}
temp->push_back(obj[n]);
std::cout << temp[0]->member_function() << std::endl;
}
Foo is a universal function.
I have a function Foo that takes a reference to a vector container. Within Foo there is a dynamic vector called temp.
I use push_back() to insert an obj into the temporary vector.
Then I wish to access that obj stored in the temporary vector in order to access its member function.
However this is where the compiler says that "expression must have pointer type".
Could somebody please explain how to rewrite this line of code.
std::cout << temp[0]->member_function() << std::endl;
temp[0]->member_function()
This treats temp as if it were an array of pointers-to-vector, which it's not.
You need to dereference temp before performing array subscripting on the result:
(*temp)[0].member_function()
Honestly, though, dynamic allocation here is pointless and is giving you a memory leak right now.
You have a vector of Name objects, and not Name*, but you use the "->" operator instead of "." which is what the compiler is telling you.
You should either try:
std::cout << (*temp)[0].member_function() << std::endl;
or make the vector elements Name*.
temp[0]->member_function()
would be correct if temp were a vector of pointers, but it isn't – it's a pointer to one vector.
And you can't use -> with a vector.
(It is equivalent to (*temp)->member_function().)
You can say
(*temp)[0].member_function()
but the better solution is usually to avoid dynamic allocation completely:
vector<Name> temp;
temp.push_back(obj[n]);
std::cout << temp[0].member_function() << std::endl;

how to print a class pointer from within a vector container in c++?

class game_list
{
public:
string name;
};
game_list *pointer;
int main()
{
vector<game_list*> mainVector;
pointer=new game_list;
cin>>pointer->name;
mainVector.push_back(pointer);
cout << "Hello world!" << endl;
cout << mainVector[1];
return 0;
}
game_list is the class declaration. vector<game_list*> is the vector containing a bunch of game_list class pointers. I am trying to print the attributes of each game_list that inside the vector. So far I have tried, mainVector[1].name but seems like it doesn't work that way.Any suggestions?
You need to dereference the pointer, just like you did above.
cout << mainVector[1]->name;
or
cout << (*(mainVector[1])).name;
Oh, and ForEveR got it right, vector indices start at 0. To get first element, you can also use mainVector.front().
However, you probably don't want to use pointers at all. If you are sure you do, use boost::ptr_vector or a vector of std smart pointers. Right now this code has a memory leak.
Firstly - indexes start from zero, so mainVector[1] - is not correct.
Secondly - if you dereference your pointer mainVector[0]->name or (*mainVector[0]).name will give correct value.
From your code, you should be able to do:
cout << mainVector[0]->name << endl;