I have class A, then I made a vector of class A;
std::vector<A> b, and i initialize it correctly.
I have one member function of another class, which has a member pointer which point to a
vector of A;
In this class, I also have a member function, and inside this member function.
I fist build a reference to the vector of class A, and initialize it use the deference of the pointer, The reason is the member reference can only assign value once, so I use pointer, but inside the member function, the syntax of reference is more clean.
the question is, in the member function, if i delete the reference to that vector, does it only delete the reference or delete the whole container the pointer point to. The container contain object not pointer.
Thanks
When the reference goes out of scope it's not going to destroy the original object.
I assume this is the situation:
class A {};
class B
{
std::vector<A>* pA;
public:
B( std::vector<A>* p ): pA(p) {}
void foo()
{
std::vector<A>& arr = *pA;
//do stuff with arr
// Arr and pA are still valid after the end of this function
}
};
int main()
{
std::vector<A> Arr;
Arr.push_back( A() );
B b( &Arr );
b.foo();
}
You should provide an example but with what you provided, it's already a big no no!
If you store a std::vector<A> you're storing actual objects of type A. When your vector grows, the items will be copied to a new memory location, therefore keeping pointers or references to items inside a vector of objects won't work as you expect.
Consider storing pointers instead (std::vector<A*>)
Deleting your pointer to a std::vector<A> should delete everything. If you switch to std::vector<A*> you should delete every object in the vector then delete the vector.
Related
I have a fundamental doubt regarding struct deallocation and pointer usage in C++.
Suppose I have the following scenario:
...
struct B
{
...
struct A a_field;
...
}
...
struct A* a_ref;
vector<struct B> b_vec;
...
// populate, use and modify b_vec elements here
...
a_ref = &(b_vec[i].a_field); // can be a one-time assignment
...
// deallocate b_vec elements here (including b_vec[i]) here
...
// using a_ref->some_field here !?!
...
Is a_ref still going to point to the last modified state of the a_field of b_vec[i], making it reliable for use later?
Or is C++-STL deallocation going to make all the fields of b_vec[i] unreliable (garbage value) when it pushes it out of the vector?
If you hold a pointer to a std::vector element that pointer can be invalidated several ways. For example, if the std::vector is destroyed or if the std::vector needs to reallocate memory when it grows.
Dereferencing a dangling pointer is undefined behavior. It's a logic error and must be avoided.
If I have a class:
Class aClass
{
vector<aClass> connections;
}
with everything else declared properly, if I were to do:
aClass a = new aClass();
aClass b = new aClass();
b.connections.push_back(a);
would this create a reference to a or would it duplicate the class.
I would like it to be a pointer to the class but I wasn't sure if I needed extra syntax to ensure this. I remember reading that when a class is declared aClass a = new aClass it is creating a pointer to the object in the heap but I wasn't sure what would happen here.
For reference this is for something like a linked list.
Also if anyone can think of a better title for this question go ahead and edit it.
connections should be vector<aClass*>, aClass a should be aClass* a.
Then, for b.connections.push_back(a);, the value of the pointer will be copied, not the pointee (i.e. the object being pointed).
I'll suggest you to use smart pointers instead of raw pointers, if you do want to use pointers, like std::vector<std::shared_ptr<aClass>>.
First, vector<aClass> is not a vector of classes, it's a vector of instances of a class.
Second, aClass a = new aClass(); is hard to make to compile in C++. In most cases a default constructed instance of a class is created simply as aClass a;, and new aClass() usually returns a pointer to a fresh instance of the class.
Third, even if you push_back an instance to the vector, it is copied.
For default-constructed objects, you can construct a fresh object at the end of the vector by resizeing the vector by 1.
Since 2011, you can construct an instance via non-default constructor (with non-empty set of construction arguments) directly inside the vector using emplace_back.
If the code is made to be compilable, which I think what you intended then:
The documentation says that is has 2 overloads
void push_back( const T& value );
void push_back( T&& value );
So as long as you don't explicitly std::move or type cast or push_back return value from a function then the first overload will trigger, which means that copying push_back will be called. Otherwise the second, moving will be called.
EDIT: type cast and std::move is the same thing under the hood. But, it preserves const correctness, thus if you were to pass const T, then std::move will make it const T&&, which is very dangerous in overload resolution.
You shouldn't pass const T&& ever, about why read here.
aClass a = new aClass();
aClass b = new aClass();
b.connections.push_back(a);
It will not even compile. As someone mentioned you should write aClass *a and aClass *b.
aClass a;
aClass b;
b.connections.push_back(a);
This will copy the value to the vector, because your vector holds aClass objects (values, not addresses). It doesn't copy any address. However, if you did something like this:
vector<aClass*> connections;
aClass *a = new aClass();
aClass *b = new aClass();
b.connections.push_back(a);
Then a vector will hold a pointers to aClass objects (instances of aClass). So in this case connections[0] will point to a object. And if you do this::
cout << connections[0]<< endl;
cout << a << endl;
Then these lines are equal. They will print the same thing (same address).
Finally, if you delete that a object:
delete a;
Then it will point to that place in memory that object was placed in, but there is no a object anymore. So you can not do:
cout << a << endl;
But you still can do:
cout << connections[0] << endl;
And it will print the same address as before.
I can't seem to write to std containers vector, map and multimap (only ones I've tried) when accessing them in structs. Here's an example of what I'm trying to do:
struct B
{
void* pp;
};
struct A
{
std::vector< B* > veEvents;
};
in a class function somewhere
A* d = new A;
B* f = new B;
d->veEvnts.push_back( f ); //<< this line crashes
Trying to access a container in this fashion crashes STD. It crashes in the STD code on lines refencing this pointers. I've tried several workarounds including typedef'ing the vector statement but that didn't work. The one that seems to have promise as a workaround was putting a function inside a struct and calling the function...
struct B
{
void* pp;
};
struct A
{
void K( B* f )
{
static std::vector< B* > veEvents;
veEvnts.push_back( f ); //<< this line crashes
}
};
in some class function
A* a = new A;
B* b = new B;
a->K(b); //This seems to work.
Is there any way around the initial problem where accessing the container declared inside a struct causes an access problem?
All right! Got to the bottom of it. Ivaylo was right about there being stack corruption. The pointer in question pointed to a vector on a class's member variable area. The vector was originally created there, copied to another struct of the same struct type on the heap but the vector still pointed to the class stack. I tried writing a deep copy but from a different class. That didn't work. So I created a struct on the heap from the start and used that to save variables on the first pass. Later, in a different class, with the struct on the heap, access to the vector works. The original struct should have been created that way in the first place. Thanks again guys. I appreciate all your help.
Is that the complete code for class 'B' ? If yes, then there is no obvious problem in code pasted. If no, then one of the possible scenarios leading to crash could be:
Class B allocates memory to *pp while creating new object but doesn't do the same while copying (i.e. shallow copy in copy constructor).
When you insert an object in vector, it calls copy constructor to copy your object into vector memory space. Due to shallow copy, both the object inserted and its counterpart inside vector share the same pointer pointed by pp.
Now the object goes out of scope and destructor deletes memory pointed by pp. Vector counterpart of this object still points to this memory and trying to access that somewhere.
When you try to do the same thing through static reference, no deletion happens (static object won't be deleted once out of scope). Both your object and corresponding object inside vector keep pointing to valid memory and no crash happens.
If I have a pointer to a struct/object, and that struct/object contains two other pointers to other objects and I want to delete the "object that contains the two pointers without destroying the pointers it holds" - how do I do that?
Pointer to Object A (Contains Pointer to Object B, Contains Pointer to Object C).
Delete Object A
Pointer to Object A is deleted, Pointer to Object B / C does still exists.
Is there something that I have to do to make this work?
UPDATE
It's for a game project, I hope this explains it. Right now, I have some "problems" even putting the two pointers to B, C inside the first Struct (A)
struct Player
{
char * Name;
Weapon* PlayerWeapon;
Armor* PlayerArmor;
};
struct Weapon
{
char * Name;
int Damage;
};
struct Armor
{
char * Name;
int Resistance;
};
And this somehow doesn't work.
Player* CreatePlayer(char * Name, Weapon* weapon, Armor* armor)
{
Player *pPlayer = new Player;
pPlayer->Name = name;
pPlayer->Weapon = weapon;
pPlayer->Armor = armor;
};
And later when a player "dies", the equipment should not be deleted.
The pointers (B & C) contained inside the pointer (A) will not be deleted unless you explicitly do it through your destructor. But you cant use the pointer A to access B & C once you delete the pointer A.
Note: You should be having a copy constructor and = overloaed operator in your class A to avoid shallow copying.
If you want to use the same armor and the weapon for someother player make sure you are not deleting the weapon and armor in your players destructor. Then you can use the same pointers for another player like this.
Weapon* weapon = CreateWeapon();
Armor* armor = CreateArmor();
Player* player1 = CreatePlayer("Alpha", weapon, armor);
delete player1;
Player* player2 = CreatePlayer("Beta", weapon, armor);
delete player2;
Pointer to Object A (Contains Pointer to Object B, Contains Pointer to
Object C). Delete Object A Pointer to Object A is deleted, Pointer to
Object B / C does still exists?
No, they are in undefined state. Anything can happen to them. May be in your system, you notice that they are existent, but assume it's just an illusion, which is not guaranteed every time.
As soon as, you delete A*, all it's content are available for next dynamic allocation. Possibly they might get allocated to some other object later on. Some system, may 0 out everything which is deleted. Again, anything can happen!
Is there something that I have to do to make this work?
Store B* and C* to other pointers before deleting A*.Then it's perfectly ok, because objects are intact and you have its addresses stored.
struct Foo
{
A *a;
B *b;
}
Foo *foo = new Foo();
delete foo; //foo now points to garbage. you can't use it
foo = nullptr; //don't use foo!
But you can do so:
Foo *foo new Foo();
//do some stuff with foo
A *a = foo->a;
B *b = foo->b;
delete foo;
foo = nullptr;
// if Foo does not destroy objects pointed by a,b in destructor you can still
//use them through a,b vars
a->doSomeStuff(); //ok
b->doSomeOtherStuff(); //ok
EDIT
In your case armor and weapon are not destroyed. You just lose pointers to them (and get the memeory leak). I suggest you to hold all your armor and weapons in some containers (like std::vector) to keep the pointers
I don't think this is possible without making a copy of a and b first.
You should avoid using "naked" pointers. It's better to use a smart pointer class such as shared_ptr or unique_ptr. They take care of new and delete, which are very tricky to get completely right unassisted. These are found in Boost, and shared_ptr is also in the TR1 library (std::tr1::) that probably came with your compiler, or just in plain std:: if your compiler is more recent.
Although you haven't said much about the program, if it's necessary to do something preserve the pointers, it sounds like the object A has the only copy of the pointers to B and C. That is a job for unique_ptr.
In C++11,
struct A_type {
std::unique_ptr< B_type > B; // Object *owns* B and C
std::unique_ptr< C_type > C;
};
std::unique_ptr< A_type > A( new A_type );
auto my_B = std::move( A->B ); // Acquire ownership away from object
auto my_C = std::move( A->B );
A.release(); // Delete object and anything it owns (at this point, nothing)
// my_B and my_C are guaranteed to be destroyed at some appropriate time
I came across a weird situation today while coding and I'm hoping someone could shed some light onto why this is happening.
I have a list of pointers to some base class:
std::list<BaseClass*> m_list;
Then I get one of the BaseClass pointers from this list
BaseClass* pBase = m_list.front();
Then I turn this base class into one of its child classes. (This is where I think the weirdness comes into play)
pBase = new ChildClass(*pBase);
The ChildClass uses the BaseClasses copy constructor to copy over all of BaseClasses fields.
Now with this ChildClass I call one of BaseClasses methods to set a field in BaseClass.
pBase->SetSomeIntMember(10);
Now if I check this int value it is 10 as expected, but it appears to only be changing it locally because if I get this same ChildClass from the list again and check it's int member it will be unchanged.
Hopefully this wasn't too tricky to follow. What makes this happen? In any situation where there is no polymorphism involved it would obviously not only be a local change as we have a pointer to the class instance. I'm guessing that I'm stomping on the pointer when I create a new ChildClass, but it definitely makes the BaseClass from the list become a ChildClass because the virtual methods still work.
pBase = new ChildClass(pBase);
This doesn't "make the BaseClass from the list become a ChildClass". It creates a new instance of ChildClass. Only changes to pBase done in ChildClass's constructor could affect what pbase pointed to before. (You cannot make one class "become an instance of a child class".)
That line of code does not change m_list at all. m_list still contains a pointer to the original BaseClass object.
You copy the value of the pointer, not a reference to the pointer.
That is,
BaseClass* pBase = m_list.front();
pBase = new ChildClass(*pBase);
is not the same as
Baseclass*& pBase_r = m_list.front();
pBase_r = new ChildClass(*pBase_r);
Remember, if you want to update the original value, you need to use references or pointers.
Note
The second example contains a memory leak since the original value of pBase is discarded before delete. To avoid such surprises, use smart pointers, e.g. std::shared_ptr<T> (C++11) or boost::shared_ptr<T> in place of T*.
Do not use std::auto_ptr<T> because its semantics are not compatible with STL containers.
So your list class should be std::list<std::shared_ptr<BaseClass>>. Another advantage here is that you can use instances of the smart pointer instead of references without messing up the internal reference count.
at first look you were just assigning the newly allocated pointer by value to pBase. The list element is actually the pointer address which got copied by value to pBase. The list element actually didn't get changed
try this instead
BaseClass** pBase = &(m_list.front());
BaseClass* pOld = *pBase;
*pBase = new ChildClass(**pBase); // you have a leak here of *pBase BTW
deleteOrCleanup(pOld); // cleanup or delete the old pBase pointer
//do what you were doing
As others have pointed out, your problem is that you're simply modifying the local copy of a pointer, and not what it's actually pointing to.
Instead of sticking raw pointers into containers and having to manually delete them (or leaking memory) when you try to replace container elements, use smart pointers.
#include <memory>
#include <list>
#include <iostream>
struct base
{
base( int a )
: x(a)
{}
int x;
};
struct derived : base
{
derived( int a )
: base(a)
{}
};
int main()
{
std::list<std::unique_ptr<base>> mylist;
mylist.push_back( std::unique_ptr<base>( new derived(10) ) );
auto pbase = mylist.front().get(); // get raw pointer to first element
std::cout << pbase->x << std::endl;
pbase = new derived( 10 * pbase->x ); // create a new derived object
mylist.front().reset( pbase ); // replace the first element, previous
// element is deleted automatically
pbase = mylist.front().get();
std::cout << pbase->x << std::endl;
// all allocated objects will be automatically deleted
// when mylist goes out of scope
}
Output:
10
100