This may sound like a newbie question. How do I call a member function of an object stored in a vector ? Supposedly, I have this class:
class A {
public:
void foo() {
std::cout << "Hello World"; }
};
Then I store some objects in a vector:
std::vector<A*> objects;
A* b;
A* c;
A* d;
objects.push_back(b);
objects.push_back(c);
objects.push_back(d);
Now I want to create a loop, in which every object stored in the vector would call it's own foo() function. How should I do this ? At first I thought I could just do something like this:
objects[2].foo();
But it seems that I can't do it like this.
std::vector::operator[] returns a reference to the object in std::vector. As your objects stores a pointer to A, you should call it:
objects[2]->foo();
Now I want to create a loop, in which every object stored in the vector would call it's own foo() function. How should I do this
The easiest loop is:
for (int i=0; i<objects.size(); ++i)
{
objects[i]->foo();
}
use C++11 for loop:
for(auto ep : objects)
{
ep->foo();
}
Or for_each(need to write a small lambda though)
for_each(objects.begin(), objects.end(), [](A* ep){ep->foo(); });
Side note:
In practice you'd better store value in STL container.
std::vector<A> objects;
for(auto e : objects)
{
ep.foo(); // call member function by "."
}
If you want to store pointer with STL container, better use smart pointer, e.g.
#include <memory>
std::vector<std::unique_ptr<A> > objects;
objects.push_back(new A());
objects.push_back(new A());
objects.clear(); // all dynamically allocated pointer elements will be de-allocated automatically
You can do this:
std::vector<A> objects;
A b;
A c;
A d;
objects.push_back(b);
objects.push_back(c);
objects.push_back(d);
objects[2].foo();
Please be a bit more specific about the exact error. I suspect maybe the whole problem was trying to reference a pointer to an object with "." instead of "->".
But yes, in general:
1) You can save an object, or a pointer to an object, in any STL container
2) You can call any public method of that object upon accessing it from the container.
You have created pointers to class A and not instances. So, you ought to access the method foo with pointer syntax.
i.e
for(int i = 0; i < 3; i++) {
objects[i]->foo();
}
In C++98 and C++03 (Since the other answers already tell you how to do it in the new standard) you can use std::for_each and the std::mem_fun adapter:
std::for_each(objects.begin(), objects.end(), std::mem_fun(&A::foo));
The std::for_each applies a function or functor to each of the elements in the range.
The std::mem_fun adapter takes a pointer to a function in its constructor and a pointer to an object as its (first) argument for operator().
This will result in the std::for_each invoking the foo() member function on each element on the array. If your vector had values on it instead of pointer you can use std::mem_fun_ref instead.
As for the error you are getting, remember that your vector is a collection of pointers so you should invoke the functions as follows:
objects[index]->foo();
Related
I have a vector as a member of a class "B". It has its set and get functions:
setVector(vector<A*>)
getVector()
I am interested in filling this vector from another function that uses an object of this class "B".
So I created new objects of class "A" and I did the following to update the vector member variable of the class "B" by mistake:
A* obj = new A;
B b;
B.getVector().push_back(obj);
What happened is that push_back did not work. In other words when I try to see the member variable using a debugger I see that the vector member variable still has a capacity of 0 as if I did not push_back anything to it.
I tried changing my implementation to be:
vector<A*> tempVector;
B b;
A* obj = new A;
tempVector.push_back(obj);
b.setVector(tempVector);
And it worked as expected.
I wanted to understand why that first behavior was a mistake? As I understand the constructor of class B should create a vector by default. So when I use the getVector() function it should return that created vector to me and then I can push_back to it. So I wanted to know what did I get wrong in this situation?
The problem is probably the return type of getVector(). Assuming it is defined as vector<A*> getVector(), it returns the vector by value, which means that you did the push_back on a copy of the vector, but not on the actual vector member.
If you want to be able to modify the vector from outside the class, all you have to do is change the function signature to pass it by reference instead: vector<A*>& getVector(). This will make sure the modifications (such as push_back) happen on the member variable.
The signature of getVector() is probably something like std::vector<A*> getVector(). This will return a copy of the actual vector. Then you push_back to the copied vector, but never modify the member variable. You want to return a reference:
std::vector<A*> &getVector();
const std::vector<A*> &getVector() const;
If I want to use the value of an element in a map as the output parameter of a function, is it better to declare it as a smart pointer or locally?
For example:
// .h
class A {
private:
// Is the below code preferred over
// std::map<int, std::unique_ptr<B>>?
std::map<int, B> map;
public:
void Func1();
// Message is the output parameter
void Func2(int, B* message);
}
// .cc
void A:: Func1() {
B b;
// Is it better to make b a smart pointer and use std::move
// to transfer the ownership to map?
map.insert(std::make_pair(1, b));
for (const auto& x : map) {
Func2(x->first, &x->second);
}
}
In the example above, is it better to declare a smart pointer for b and pass the pointer to Func2 instead?
Thanks,
std::map makes copies of what you put in it1, so map owns the copy of b provided to func2. There is no need for smart pointers here as map will handle destruction of all stored Bs.
In fact there is no need for pointers at all. func2 could be void Func2(int, B & message); and use a reference.
1 You can store a pointer in a std::map, and the std::map will contain a copy of the pointer. The data pointed at is not copied and needs external management to handle destruction. This is a good case for using a smart pointer, but storing pointers in a container defeats many of the benefits of using a container in the first place and is best avoided.
I create a vector A and want to copy to a vector B in another class by using below method, is it a correct way? The vector A may be destroyed! I searched in google, but not found the good solution and meaningful explanation. Thanks everyone
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Yes and no, you are passing the vector by value:
void StateInit(vector<CButton*> listBtn)
{
_m_pListBtn = listBtn;
};
Wich means that listBtn is a copy of vector A (asuming we are calling vector A the one passed as parameter of StateInit), if you delete vector A, vector B will still have the collection of pointers and they will be valid since the destruction of a vector of pointers doesnt delete the pointed objects because it cant possible now how (should it call, delete, delete[], free?).
Do keep in mind that if you modify/delete one of the elements from vector A (using the pointers on the vector), that element will be modified in vector B (since its a pointer to the same element).
Im not sure what is your intend with this, but if you want to copy the whole vector, you should implement a clone mechanism for the objects and then copy them using transform:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
Then just:
void StateInit(vector<CButton*> listBtn)
{
transform(listBtn.begin(), listBtn.end(), back_inserter(_m_pListBtn), cloneFunctor());
};
IF your intention is not to clone it but to share the pointers you should pass the vector as pointer or reference:
void StateInit(const vector<CButton*>& listBtn)
{
_m_pListBtn = listBtn;
};
A better way is to iterate on the new vector and push_back the elements to your vector.
See example code: std::vector::begin
Consider the following code:
#include <vector>
using namespace std;
struct foo
{
void bar()
{
}
};
int main()
{
{
vector<foo*> a;
a.push_back(new foo());
a.push_back(new foo());
a.push_back(new foo());
vector<foo*>::const_iterator itr = a.begin();
(*itr)->bar(); // compiles - this becomes more confusing
// when found in a const method. On first
// glance, one will (or at least me) may
// assume that bar() must be const if the
// method where it is being called from is
// const
// The above compiles because internally, this is what happens
// (ignore the fact that the pointer has not been newd)
foo* const * element;
(*element)->bar(); // compiles
// What I would expect however (maybe it is just me) is for const_iterator
// to behave something like this
const foo* const_element;
const_element->bar(); // compile error
}
{
vector<foo> a;
a.resize(10);
vector<foo>::const_iterator itr = a.begin();
itr->bar(); // compile error
}
}
I understand why it can be called. The const_iterator stores the const-ness like this: const T* which for the pointer translates to foo* const * and for the object foo const *.
So my question is, why are we allowed to call a non-const member function from a const_iterator? Isn't it more intuitive to not allow the call to a non-const member function from a const_iterator? Shouldn't the design of iterators with the const option prevent this behaviour?
The more important question now is this: What if I want const_iterator to disallow calling of non-const member functions of the pointed to object?
Shouldn't the design of iterators with the const option prevent this behaviour?
It does. You're just expecting it to be a different operation.
As you discovered, a container of pointers... contains pointers, not objects. Therefore, a const_iterator to such pointers means that the pointers are constant, not the objects they point to.
That's not going to change, nor should it. The standard library containers are generally designed to contain full-fledged objects, not pointers. So they shouldn't encourage users to make vectors of pointers and other dubious constructs.
If you really need a vector to contain pointers, then you should use a container that is actually designed to do so. Like Boost's pointer container classes. Their const_iterators make the objects being pointed to const properly. They also do other useful things, like own the objects they point to (so that they are properly deleted) and so forth.
You have a vector of pointers, pointers don't have member functions so you're not calling a member function on something that is stored in the vector.
The type of object that you get when you dereference a pointer depends on the type of that pointer. Your vector is a vector of non-const pointers so when you derefence any pointer from your container you always get a non-const reference to the pointed to object.
If you want a vector of pointers then you have two options. You can create a vector<const foo*> instead and you will never be able to retrieve a non-const reference to any pointer to object or, if you need to be able to get non-const references from non-const instances of your vector you will have to create an object that contains the vector as a private member variable and gives you the access that you want via a pass-through interface.
If your vector is supposed to own the objects that it holds pointers to you could consider simple vector<foo> instead or, if dynamic allocation is required, a boost::ptr_vector<foo>.
So my question is, why are we allowed to call a non-const member function from a const_iterator?
"Constant iterator" means container element is constant. It doesn't mean that if that element is a pointer, the pointed object is also constant.
What if I want const_iterator to disallow calling of non-const member functions of the pointed to object?
I wouldn't want to encourage you using raw pointers like this, but if you really have to, make it a container of pointers to const objects.
std::vector<const foo*> a;
// ...
auto itr = a.cbegin();
(*itr)->bar(); // Compiler error (calling a non-const method on const object).
Of course, in that case the following would also be disallowed:
std::vector<const foo*> a;
// ...
auto itr = a.begin();
(*itr)->bar(); // Compiler error.
I have a class that has a vector of objects. What do I need to do to return one of this objects and change it outside the class, keeping the changings? Is it possible to do with regular pointers? Is there a standard procedure? (And yes, my background is in Java.)
Your question is a bit vague, but here's an example:
class foo
{
public:
foo()
{
vec.resize(100);
}
// normally would be operator[]
int& get(size_t pIndex)
{ // the return type is a reference. think of it as an alias
return vec[pIndex]; // now the return value is an alias to this value
}
private:
std::vector<int> vec;
};
foo f;
f.get(10) = 5;
// f.get(10) returned an alias to f.vec[10], so this is equivalent to
// f.vec[10] = 5
The FAQ has a nice section on references.
Also, if you're new to C++ don't try learn with online resources. If you haven't got a book, you should, they're really the only good way to learn the language.
If the vector holds pointers to objects any change to one of the objects returned from the vector (or more accurately the object pointed) will affect the instance inside the vector as well.
If you have std::vector where A is your class, you could return a std::vector::iterator.
class A {
public: int a;
};
std::vector<A> v = ...;
std::vector<A>::iterator it = v.begin(); // access to the first element
it = v.begin() + 5; // access to the 5-th element (vector can do random access)
// 'it' can now be used elsewhere
it->a = 0; // changes are reflected in the object inside the vector
*it = A(); // changes the object hold by the vector
Beware, that iterators may be invalidated, if the vector changes!
You need to return either a reference or a pointer to the object.
type &getref(); // "type &" is a reference
type *getptr(); // "type *" is a pointer
The caller will then have access to the underlying object.
But you then need to make sure the object does not move (which can have if a vector has to grow). You may want to think about using a std::list instead.