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
Related
Let's say I have a struct "A" with four members there. The four members are named:
one
two
three
four
I also have a struct "B" with five members there. Four of the five members come from struct A.
Then I have a vector with struct B pointers. I add every created struct B to this vector.
This looks like this:
std :: vector <B *> vec;
for (A& a : input.buffer())
{
B b =
{
a.one, a.two, a.three, a.four, random value
};
vec.push_back (& b);
}
function_which_needs_a_const_pointer_to_the_first_element_and_size_of_vector (vec.front (), vec.size ());
Now I have used a number of std :: cout at different points in the code.
I print the following values:
a.one = 1304505
b.one (just before the push_back) = 1304505
vec [0] -> one (after the push_back) = 24050434
So as you can see I am troubled by values that change after adding to the vector, as a result of which the rest of the code can no longer function correctly.
Does anyone have any idea how I can solve this? I probably do something stupid.
I tried google now for two days, but nothing seemed to help.
Thanks to some of your comments I know now that there are dangling pointers. If I make it a vector of shared pointers instead of raw pointers, I will have a invalid conversion from shared pointer to const raw pointer error.
So now, we know the issue. But what is the best way to fix it? Because I am not allowed to touch that const raw pointer in that function.
Before you all press the down vote button; None of you is still able to give me the correct solution.
The immediate cause of the problem is that your objects don't exist when you try to use them.
You should never store a pointer you acquire with & for later use.
The more fundamental source of the problem is that you have misunderstood the exercise.
The function you're not allowed to modify wants a pointer to the vector's first element, but vec.front() is not a pointer to the vector's first element - it is the vector's first element.
(This element happens to be a pointer, but it's not a pointer to the beginning of the vector).
You can get pointer to vec's first element with &vec[0] or vec.data() or &vec.front().
This is what you should pass to the function, and your vector's type should be vector<B>.
That is,
std::vector<B> vec;
for (A& a: input.buffer())
{
B b ={ a.one, a.two, a.three, a.four, random value };
vec.push_back(b);
}
function_with_long_name(vec.data(), vec.size());
When you vec.push_back (& b);, you are pushing a pointer to an object that is about to cease to exist. There isn't a B to point to when you vec[0]->one
You pass an address of local variable that becomes unavailable when going out of scope, that's why your vector will contain pointers to memory with no data available.
See comments in code.
std :: vector <B > vec; // just copy them all
for (A& a : input.buffer())
{
B b =
{
a.one, a.two, a.three, a.four, random value
};
vec.push_back (b); //not passing by reference anymore, just copy.
}
function_which_needs_a_const_pointer_to_the_first_element_and_size_of_vector (&vec.front (), vec.size ()); // Passing the reference of vec->front for the first element of the vector.
In the past I always created a map like this:
class TestClass
{
private:
std::map<int,int> *mapA;
};
TestClass::TestClass
{
mapA = new std::map<int,int>();
}
TestClass::~TestClass
{
mapA->clear(); // not necessary
delete mapA;
}
So, now I read all over the place at Stackoverflow: avoid pointers as often as possible
Currently I want to create the map without pointer and new (no need to delete the object by myself and less danger of getting some memory leak)!
class TestClass
{
public:
TestClass() : mapA() // this is also needed?
{};
private:
std::map<int,int> mapA;
};
Any further steps for correct creation of the map necessary?
Thanks for any help and/or clarification!
Nope that's it, and you don't need to explicitly initialize it in the constructor.
As zennehoy says, it is not necessary to initialize the map in the TestClass constructor.
Let me note a difference between the two implementations:
In the first one, the TestClass, as it is currently written, is not copyable without undesirable effects because the raw pointer to the dynamically allocated map is copied:
TestClass *A = new TestClass; // A has a map
TestClass *B = new TestClass(A); // B shares the map with A!
delete A; // this deletes A's map (in destructor)
delete B; // this deletes A's map again! wrong
In your second implementation, that does not happen because the map, and not just its address, is copied completely.
To solve that issue in your first implementation, you should use a shared pointer, or do the work yourself by implementing the operator= and the copy constructor. Or, if you want to really share the map between copied instances, you should implement a reference counting mechanism.
I have the following code to store objects of type LVA in a vector.
I've implemented a method for adding a LVA Object to the vector.
First question: Is it okay if i use a reference to the LVA object in this method?
Now i want to implement a method for the deletion of a LVA object. I want to have the following method signature: void RemoveLVA(LVA& lva). How can I implement this method? i.e. How can i find the right object in the vector to delete it?
Manager.h
class Manager {
public:
Manager();
Manager(const Manager& orig);
virtual ~Manager();
vector<LVA> GetLvas() const;
void AddLva(LVA& lva);
private:
vector<LVA> lvas;
};
Manager.cpp:
#include "Manager.h"
Manager::Manager() {
}
Manager::Manager(const Manager& orig) {
}
Manager::~Manager() {
}
vector<LVA> Manager::GetLvas() const {
return lvas;
}
void Manager::AddLva(LVA& lva) {
lvas.push_back(lva);
}
Is it okay if i use a reference to the LVA object in AddLva(LVA& lva)?
Yes, std::vector will have a copy of your original object after push_back() is complete.
How can I implement RemoveLVA(LVA& lva)?
You will need to find the object in your vector. (You may use std::find() if operator==() is defined for LVA.) Then invoke the erase() function for your vector.
Is it okay if i use a reference to the LVA object in this method?
No problem. You are actually doing a copy by a push_back operation.
Without knowing more about LVA, it's hard to be precise, but
you probably want a const reference for AddLva, since you're
not modifying it in the function (and you may want to pass
a temporary).
For removal: you'll have to define some sort of
equivalence function over LVA is you want to remove a matching
element. This can be LVA::operator==, or some other object or
function: in the first case, you use std::find to find the
position, and in the second, std::find_if. If the vector can contain
more than one matching element, you might want to look into std::remove or std::remove_if.
Your insertion method is right, but don't forget that only a copy from your LVA object is inserted in the vector. it means than in the RemoveLVA method, you will need to use somthing like an operator== overload to std::find the vector's object which matches your parameter, and then deleting it.
You may prefer to insert pointers or std::shared_ptr of LVA in your vector. No object copy will then occur, and the search of an object will fall back to a comparison of pointer, given you keep the pointer somewhere else in your program (2 objects with same contents and different stack or heap locations would then compare to false).
Yes, AddLva can take a reference, although it would typically take a const reference:
void Manager::AddLva(const LVA& lva) {
lvas.push_back(lva);
}
Note however that if you are expecting that the reference is added to the vector, this isn't doing that. A copy of the object lva refers to is made, and that copy is added to the vector.
Yes it's Ok to pass the LVA object as ref in your add and remove method. You could also declare those parameters as 'const' because I suppose add and remove will not affect the object .
for the remove method
void RemoveLVA(const LVA& lva)
{
std::vector<LVA>::iterator position =
std::find(lvas.begin(), lvas.end(), lva);
if (position != lvas.end())
{
lvas.erase(position);
}
}
but LVA class must have an == operator.
good luck.
I'm new to C++ and have a question regarding memory management.
In the header, I have this:
std::vector<Obstacle::Obstacle*> obstacles;
and in the .cpp I do this:
Circle *circle = new Circle(x, y, radius);
obstacles.push_back(circle);
where Circle is a subclass of Obstacle.
My question is when should I call delete on the elements which are in the vector? I have heard each new should be balanced by a delete. Do I need to in the destructor loop through the vector and call delete on each element? Isn't there a more elegant way?
Thanks
You have to call delete on the elements before you clear the vector, or before the vector goes out of scope iff the vector owns the objects pointed at. A more elegant solution is to have the vector hold smart pointers. The particular type of smart pointer should depend on the ownership policy.
For example, a vector owning the pointed-at objects should use C++11 std::unique_ptr:
std::vector<std::unique_ptr<Obstacle>> obstacles;
Of course, all of the above is under the assumption that you actually have strong reasons to use pointers. Often the best solution is the simplest ones: hold items by value:
std::vector<SomeType> things;
Note that this doesn't apply in your case, where you are storing pointers to objects derived from a base class, since storing values of base type would result in object slicing.
Edit: One simple way to ensure the elements are deleted when the vector goes out of scope is to write a scope guard class:
template <typename CONTAINER>
struct PtrContainerGuard
{
PtrContainerGuard(CONTAINER& container) : c_(container) {}
~PtrContainerGuard()
{
for (typename CONTAINER::iterator it = c_.begin(); it != c_.end(); ++it)
delete (*it);
}
private:
CONTAINER& c_;
}
then
std::vector<Obstacle*> obstacles;
PtrContainerGuard<std::vector::Obstacle*> p(obstacles);
Why not use shared_ptr? You don't have to create new objects and worry about deleting them if you use them.
typedef shared_ptr<Obstacle> ObstaclePtr;
int main()
{
std::vector<ObstaclePtr> obstacles;
//Create objets using shared_ptr and push them in vector
ObstaclePtr obstacle1(new Circle());
obstacles.push_back(obstacle1);
ObstaclePtr obstacle2(new Circle());
obstacles.push_back(obstacle2);
//When vector obstacles goes out of scope here, all circles inside are destructed!
}
Yes, there is a more elegant way. Throw away all your pointers.
std::vector<Obstacle::Obstacle> obstacles;
Circle circle(x, y, radius);
obstacls.push_back(circle);
Nothing was new'ed, nothing needs to be deleted, you save a memory allocation, and access to the objects stored in the vector becomes more efficient.
Also, your code will no longer make the eyes bleed of more experienced C++ developers.
All in all, I call that a win. :)
I want to ask whether there are some problems with the copy for the vector of pointer items. Do I need to strcpy or memcpy because there may be depth copy problem?
For instance:
Class B;
Class A
{
....
private:
std::vector<B*> bvec;
public:
void setB(std::vector<B*>& value)
{
this->bvec = value;
}
};
void main()
{
....
std::vector<const B*> value; // and already has values
A a;
a.setB(value);
}
This example only assign the value to the class variable bvec inside A class. Do I need to use memcpy since I found that std::vector bvec; has pointer items? I am confused with the depth copy in C++, could you make me clear about that? Thank you.
Think about this, if you remove and delete an item from the vector value after you call setB, then the vector in A will have a pointer that is no longer valid.
So either you need to do a "deep copy", have guarantees that the above scenario will never happen, or use shared smart pointers like std::shared_ptr instead of raw pointers. If you need pointers, I would recommend the last.
There is another alternative, and that is to store the vector in A as a reference to the real vector. However, this has other problems, like the real vector needs to be valid through the lifetime of the object. But here too you can use smart pointers, and allocate the vector dynamically.
It is unlikely you need strcpy or memcpy to solve your problem. However, I'm not sure what your problem is.
I will try to explain copying as it relates to std::vector.
When you assign bvev to value in setB you are making a deep copy. This means all of the elements in the vector are copied from value to bvec. If you have a vector of objects, each object is copied. If you have a vector of pointers, each pointer is copied.
Another option is to simply copy the pointer to the vector if you wish to reference the elements later on. Just be careful to manage the lifetimes properly!
I hope that helps!
You probably want to define your copy constructor for class A to ensure the problem your asking about is handled correctly (though not by using memcpy or strcpy). Always follow the rule of three here. I'm pretty sure with std::vector your good, but if not, then use a for loop instead of memcpy