Access pointer methods of pointer vector - c++

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

Related

Accessing an element of a vector created dynamically

vector <int> * v = new vector <int>;
v -> push_back (1);
cout << v[0]<< endl; // error
Why can't I access the first element? I get this error
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'std::vector')|
Why would you allocate a vector with new? The main point of using vectors is to avoid having to use new.
vector<int> v;
v.push_back(1);
cout << v[0] << endl;
If for some strange reason you decide you really must use a pointer, then you can do
vector<int>* v = new vector<int>;
v->push_back(1);
cout << (*v)[0] << endl;
But really, allocating a vector with new makes little sense.
Perhaps you were a Java programmer before you tried C++? If so then don't try to program C++ in a Java style, they are very different languages. You will get into a horrible mess if you do.
Because v is pointer to vector, but not reference or vector itself. Therefore v[0] gives you not what you likely expect. It gives you vector object itself. For which there is no stream output operator<< defined. You must use (*v)[0].
It's very unlikely that you need to dynamically allocate a vector like this, but if you do have a pointer to a vector:
vector<int>* v = new vector<int>;
then the correct syntax to invoke the member functions is:
// dereferencing the pointer and then using the member functions
(*v).push_back(1);
cout << (*v)[0] << endl;
or
// using -> with the correct names of the member functions
v->push_back(1);
cout << v->operator[](0) << endl;

How do you create a vector of function pointers that can take different arguments?

I'm trying to learn how to store functions (or rather pointers to functions) in std::vector. I have this code:
#include <iostream>
#include <vector>
void x(int i)
{
std::cout << "x is " << i << std::endl;
}
void y(int i, int j)
{
std::cout << "y is " << i << " and " << "j" << std::endl;
}
int main()
{
std::vector<void(*)(int)> V;
V.push_back(x);
V[0](1);
return 0;
}
This works perfectly but the problem is that I can't push_back function y into the same vector since it takes 2 integers instead of one.
What should I do to store both functions in the same vector?
There is no good way to do what you want, but you can do it.
Write an augmented variant (std or boost or hand rolled tagged typesafe union) that supports implicit cast-from with exception if you get the type wrong (feel free to support conversion between types if desired). Call this poly_arg<Ts...>
Write a type eraser that takes an arg type as a template parameter. It then takes a function pointer at construction, and type erases calling it with a vector of just the right length of arguments. (Or a function object and an arg count range). It then has a vararg operator() that forwards its arguments into a vector of its arg type, then tries to call using the above type erasure. If the wrong number of arguments is passed, it throws an exception. Call this vararg_func<T>.
Store a vector of vararg_func<poly_arg<int, double, std::string>> (list of 3 types is just an example). This can store void(*)(int) and void(*)(int,int) and void(*)(std::string, double, int) and void(*)() etc, and you can invoke it. If you get the argument count wrong, you get an exception (from vararg func). If you get an argument type wrong, exception (from poly arg). If you pass an incompatible function pointer, compile error at push_back (which is great!)
If you only need to support int args you can skip poly_arg and store vararg_func<int> instead.
I think this is a bad plan.
You very very rarely want to treat functions with different numbers and types of arguments uniformly. The few legitimate cases are best handled with two coupled type erasing systems (like efficient massive customization point tables with non-uniform signatures) that hide the type unsafety internally.
Instead this plan matches your requirements, which forces type unsafety in its interface and pollutes your code with "dunno, maybe it will work" calls.
If you want help implementing those type erasers, realize that I both know how to write them and how they solved your problem and in my opinion they are a really bad idea. If that fails to deter you, go and learn about type erasure in C++ and value-type polymorphism and how std::function works. Try to write a toy std::function. Play with a "view-only" and "move-only" version. Try a zero-allocation with bounded function object size. That should take a few weeks or years.
Now write some more simple cases, like printing to an ostream. Get good enough at it. At which point vararg_func shoukd be challenging but doable; try it. If it fails, ask SO to help, including your attempt.
poly_arg should be easy in comparison.
What you want is neither possible nor reasonable. It's not possible because function pointers are typed, and a pointer to a void(int, int) is a different type from a pointer to a void(int). vector is a homogeneous container; all of its elements must be the same type. And the two types are unrelated; you cannot cast the pointer to one type into a pointer to another and expect calling it to work.
The best you can do is use a variant of pointers to different function types. Now, I have no idea how you would call those functions, since the different types take different parameter lists. How could you call it through a visitor functor? Do you have enough parameters to forward to the function in question? If not, then what's the point?
Unless you know a priori that index X in the list has a specific parameter list, and you have those parameters to pass to it, then there is no effective way to call it. And if you do know that, then what you probably want is a tuple or struct of function pointers, not a runtime container of them.
You could use std::variant if you have access to C++17:
#include <variant>
std::vector<std::variant<void(*)(int), void(*)(int, int)>> V;
V.push_back(x);
V.push_back(y);
But this gets messy real fast (if you want to add even more function types etc) and since there are different parameter types and amounts there's no sure way to uniformly call them from out of the vector unless you also store their type information and std::get the correct variant.
First of all, i would recomend using std::function over function pointers. They are more generic and can be filled with a function pointer, function object or lambda expression. The typical useage looks like this:
#include <iostream>
#include <functional>
struct Funktor { // This is a callable class/object
void operator()() {
std::cout << "Funktor called." << std::endl;
}
};
void function() { // Normal function
std::cout << "Function called." << std::endl;
};
int main()
{
std::function<void()> lambdaFunction = [](){ std::cout << "lambda function executed." << std::endl;}; // And a lambda expression (fancy way to write a function where you need it)
std::function<void()> functionPointer = &function;
std::function<void()> callableObject = Funktor();
//This is the way you call functions with a std::function object, just like with a normal function
lambdaFunction();
functionPointer();
callableObject();
return 0;
}
But this does not solve your problem of storing functions with different arguments in a std::vector. Since they have a differen signature you have to treat them as if they are different types. Like int and std::string.
To store elements with different types, the STL offers std::tuple. You can use this one to achieve your goal.
#include <iostream>
#include <functional>
#include <tuple>
int main()
{
// std::tuple takes multiple template arguments. Each corresponds to one element in the tuple
std::tuple<
std::function<void()>,
std::function<void(int)>
> functionTuple;
// To access a element of the tuple we call std::get<i> on the tuple
// This will return a reference to the element in the tuple and we
// can overwrite it with whatever we want
std::get<0>(functionTuple) = [](){
std::cout << "Function without arguments." << std::endl;
};
std::get<1>(functionTuple) = [](int arg){
std::cout << "Function without int as argument. Arg = " << arg << std::endl;
};
// We use std::get to get the function and the call it.
// The the trailing '()' and '(5)' are the actual function calls,
// just like in the example above
std::get<0>(functionTuple)();
std::get<1>(functionTuple)(5);
// You can also use std::get<...> with a type as argument.
// Have a look in the docs. Its a very nice feature of tuples
return 0;
}
And if you want to achieve both, different arguments and multiple functions, you can combine std::tuple and std::vector:
#include <iostream>
#include <functional>
#include <tuple>
#include <vector>
int main()
{
std::tuple<
std::vector<std::function<void()>>,
std::vector<std::function<void(int)>>
> functionTuple;
// We use push_back in this example, since we deal with vectors.
std::get<0>(functionTuple).push_back([](){
std::cout << "Function without arguments." << std::endl;
});
std::get<1>(functionTuple).push_back([](int arg){
std::cout << "Function without int as argument. Arg = " << arg << std::endl;
});
std::get<1>(functionTuple).push_back([](int arg){
std::cout << "Another function without int as argument. Arg = " << arg << std::endl;
});
std::get<0>(functionTuple).front()();
int i = 5;
// And we use foreach, to loop over all functions which take one integer as argument
for(auto& f : std::get<1>(functionTuple)) {
f(i);
i += 5;
}
return 0;
}
That all beeing said, I will add a word of caution. Function pointers/objects and lambdas are only one tool. They are very flexible and powerful and because of this can lead you into a rabbit hole of unexpected behaviour and errors. If you do not plan to write very generic algorithms and go deep into template metaprogramming, this tool is most likely not the best to do the job. Going for different solutions like the command pattern can make your life much easier.
Another possibility would be to alter the signature of 'x' to match that of 'y', by adding an additional int parameter that could be ignored by the body of x.
Easy. Place the arguments into a structure or base class.
If you use a pointer to a base class, you can expand the genericity.
An old fashioned method is to pass a void pointer and have the function cast it correctly.
In fact you cannot push different pointer to function of different signatures into a vector as long as you cannot push different objects of different types into a vector.
class A{};
class B{};
A aObj;
B bObj;
std::vector<class A> vecA;
vecA.push_back(aObj); // ok
vecA.push_back(vecB); // error
Push only objects with the same type as your vector instance require:
#include "stdafx.h"
#include <iostream>
#include <vector>
void Foo() { std::cout << "Foo()" << std::endl; }
void Foo2() { std::cout << "Foo2()" << std::endl; }
int Bar(float) { std::cout << "Bar(float)" << std::endl; return 0; }
double Baz(int, int) { std::cout << "Baz(int, int)" << std::endl; return 0; }
int main(){
std::system("color 1f");
typedef void(*pFunc1)();
typedef int(*pFunc2)(float);
typedef double(*pFunc3)(int, int);
pFunc1 pFn1 = Foo;
pFunc1 pFn2 = Foo2;
//pFunc1 pFn3 = Bar; // error here I guess you k now why
std::vector<pFunc1> pvcFunc1;
std::vector<pFunc2> pvcFunc2;
std::vector<pFunc3> pvcFunc3;
pvcFunc1.push_back(pFn1);
pvcFunc1.push_back(pFn2);
for (int i(0); i < pvcFunc1.size(); i++) {
pvcFunc1[i]();
}
std::cout << std::endl << std::endl << std::endl;
std::cin.get();
return 0;
}
I wouldn't do that.
I can't tell you whether using both functions in one vector is possible or not -- I'm pretty sure it isn't.
You should instead make a class and use a vector of objects.

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;

C++ STL Vector Iterator accessing members of an Object

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.