C++: updating a vector member variable of a class - c++

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;

Related

What happens when using pass by reference and member initialization lists in C++ classes?

Okay, so I have a large vector say
vector<vector<vector<int>>>
of 10000 by 10000 by 10000.
I have a class which has such a vector as a private member variable:
class foo {
private:
vector<vector<vector<int>>> myvector
};
I have a constructor for my class that uses pass by reference and initializer list:
foo(vector<vector<vector<int>>> &myvector_in) : myvector(myvector_in);
I want to know what's exactly happening in terms of memory usage. Is the private myvector the same as the one that was originally declared, or is it a copy.
Basically, I want to know if there are ever two version of myvector in memory.
Thank You!
Here is a fishing tip.
Fairly easy to answer yourself. Set [0][0][0] of myvector_in to a known value. Invoke the constructor and inside it also set [0][0][0] but of myvector to a different value. Once the constructor has returned, print the content of myvector_in. If it's the same as the one you original set you must conclude that the two vectors are different entities, thus one was copied into a different one. If they are the same than you can conclude they are in fact the same instances.
You could also print addresses to get a better sense of what's what.
I must point out, the memory requirement mention in your original question are in the realm of super computer, you got one?
You have a member of type vector<vector<vector<int>>> and initialize it with another vector<vector<vector<int>>>. How would it be possible not to have said data twice in memory? Thats more a matter of logic than a matter of c++.
Alternatives
You could store a pointer vector<vector<vector<int>>>* or a reference vector<vector<vector<int>>>& to the vector in an appropriate class member. Or use one of the smart pointers to do so. In any of these cases some serious thinking about memory management is a good idea.
Or you use a move constructor, which is moving the passed in vector in your member vector.
using vec = std::vector<std::vector<std::vector<int>>>;
class foo {
public:
foo() = delete;
foo(const vec&) = delete;
foo(vec&& myvector_in) : myvector(std::move(myvector_in)) {};
private:
vec myvector;
};
Of course that will render that argument passed to the constructor useless but that a trivial consequence of the not-copying you want.
You can pass your vector to that constructor if you first cast it to an rvalue using std::move:
foo my_foo(std::move(test));
The easy way of addressing this issue in C++11 (and newer) is to accept the constructor argument by value:
struct foo {
using vec=std::vector<std::vector<std::vector<int>>>; // from DrSvanHay
foo(vec v) : myvector(std::move(v)) {}
private:
vec myvector;
};
Surprisingly, this actually minimizes copies:
If the client has a vector cv;, cv gets copied into the parameter v, but that copy was necessary to have cv and foo::myvector upon completion.
If the client passes std::move(cv), cv gets moved into v and there is no copy.
If the client passes make_vector(...), the parameter v is move-initialized from the return value (or, in C++17, is the return value).
(In all these cases, v is then moved into foo::myvector, of course.)

Calling sort() on a vector that's a member of a class "No matching function for call to swap()"

I have a class A declared as:
class A {
public:
vector<int> vec;
};
Running the following code:
const A *a = new A();
sort(a->vec.begin(), a->vec.end());
gives me the error:
algorithm: No matching call to swap()
in Xcode.
Any clue as to why this is happening?
const A *a means "pointer to const A, and that means the object pointed at by a cannot be modified via a. sort modifies the elements of the iteration range passed to it. Since these elements are owned by the object pointed at by a, they cannot be modified via a.
So, you cannot call sort the vector a->vec. You need to find a different approach.

error when adding into vector of pointers

class A{
Add(const B&);
vector <B*> vect;
};
A & A::Add(const B& obj){
vect.push_back(&obj);
return *this;
}
here I am getting fpermissive error, because argument of push_back is constant, how do I get rid of this?
I tried to create local copy in Add such as
B tmp;
tmp = obj;
vect.push_back(&tmp);
but I am not sure about this, as program step out of this method Add, tmp gets destructed, and adress in vector will point to invalid place in memory?
Your problem arises from API inconsistency. 2 options here:
Drop the const from the signature of Add: Add(B&)
Store const B* pointers in the vector: vector<const B*> vect;
The first option will allow to modify the contents of your objects while the second one will forbid it. The choice depends on your program logic.
Your problem is that if you provide a const reference as the function parameter of Add you are telling the compiler that whatever you are passing is never going to be changed as an effect of that function.
On the other hand you try to store a non-const pointer in the vector which means that the users of that vector are allowed to change the value correlated to that pointer.
To get rid of the error you have to decide what is the type of behaviour you actually want from your program:
if you want to store read-only references to your "B" objects then you have to store them as const pointer in the vector. If you want the users of that vector to be able to use non-const functions of B, that is to change B, you have to pass it to the Add function as non-const reference.

Calling member functions of an object stored in a vector

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();

Copy from vector<pointer*> to vector<pointer*> in C++

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