Do class objects declared on the stack have the same lifetime as other stack variables?
I have this code:
#include <stdio.h>
#include <vector>
using std::vector;
#include <string>
using std::string;
class Child;
class Parent
{
public:
Parent(string s) : name(s) { };
vector<Child> children;
string name;
};
class Child
{
public:
Child() { /* I need this for serialization */ };
Child(Parent *p) : parent(p) { };
Parent *parent;
};
Parent
family()
{
Parent p("John Doe");
int i;
printf("family:\n\tparent: 0x%x\n\ti: %x\n", &p, &i);
for (i = 0; i < 2; ++i)
p.children.push_back(Child(&p));
return p;
}
int
main(void)
{
Parent p = family();
printf("main:\n\tparent: 0x%x\n", &p);
for (unsigned int i = 0; i < p.children.size(); ++i)
printf
(
"\t\tchild[%d]: parent: 0x%x parent.name '%s'\n",
i,
p.children[i].parent,
p.children[i].parent->name.c_str()
);
return 0;
}
My questions:
In function family, is Parent p declared on the stack? From looking at the output, it would seem so
Each created Child goes on the stack too, right?
When I create each Child instance, I pass it a pointer to a stack variable. I imagine this is a big no-no, because stack variables are guaranteed to live only until the end of the function. After that the stack should get popped and the variables will be destroyed. Is this correct?
vector.push_back() passes arguments by reference, so at the end of the family function, p.children just contains references to the local variables, right?
Why is it all working? In main, why can I access the parent and each of its children? Is it all because the local variables from family are still intact and haven't been overwritten by some subsequent function call?
I think I'm misunderstanding where stuff lives in memory in C++. I'd really like to be pointed a resource that explains it well. Thanks in advance.
EDIT
Output from compiling the source and running:
misha#misha-K42Jr:~/Desktop/stackoverflow$ ./a.out
family:
parent: 0x2aa47470
i: 2aa47438
main:
parent: 0x2aa47470
child[0]: parent: 0x2aa47470 parent.name 'John Doe'
child[1]: parent: 0x2aa47470 parent.name 'John Doe'
It all works because vector makes copies of everything that you push_back. Your family function is also returning a copy, so even though the stack variable p goes out of scope and gets destroyed, the copy is valid.
I should point out that the Parent pointers retained by the Child objects will be invalid after the end of the family function. Since you didn't explicitly create a copy constructor in Child, one was generated for you automatically by the compiler, and it does a straight copy of the pointer; the pointer will point to an invalid object once p goes out of scope.
The Child objects that are in the vector survive for the reason that Mark Ransom pointed out, but the pointer to Parent * that each Child contains (which points to p) becomes invalid just as you expected.
If it appears to work, what likely happend is the compiler's optimizer inlined family(), and then combined the storage of main(){p} and family(){p} to avoid copying the returned object. This optimization would be likely even without inlining, but nearly certain with it.
It's easy to see why it would be allowed in this case, since your Parent class doesn't customize the copy constructor, but it's actually allowed regardless. The C++ standard makes special reference to return value optimization, and permits the compiler to pretend that a copy constructor has no side effects, even if it can't prove this.
To fix this, the Parent needs to be allocated on the heap, and some other provision would need to be made to free it. Assuming that no time-travel is involved (so that no object can become its own ancestor), this could be easily accomplished by using tr1::shared_ptr (or boost::shared_pointer for pre-TR1 compilers) for the pointer each child holds to its parent.
In function family, is Parent p declared on the stack? From looking at the output, it would seem so
Yes, that's right. However, since it is clear that p is returned by the function family, the compiler will use it to store the result instead of actually copying it into left-hand-side of Parent p = family();. In other words, it doesn't create the p in family() and then copies it because that would be wasteful. Instead, it creates the p in main() and uses it as p in family() to store the result directly (avoiding the useless copy).
Each created Child goes on the stack too, right?
No, std::vector dynamically allocates memory to store its elements (as indicated by the fact that the size can change at run-time). So the instances of Child that are pushed to the vector container are store in dynamically allocated memory (the Heap).
When I create each Child instance, I pass it a pointer to a stack variable. I imagine this is a big no-no, because stack variables are guaranteed to live only until the end of the function. After that the stack should get popped and the variables will be destroyed. Is this correct?
Yes that is correct. You should avoid this situation because it can be unsafe. One good way to avoid this and still have the capability of storing a pointer to the Parent in the Child object is to make the Parent non-copyable (making both copy-constructor and assignment operator private and without an implementation). This will have the effect that since a Parent cannot be copied and since the parent contains its children, the pointer to parent that the children have will never go invalid as long as the children are not destroyed (since they are destroyed along with their parent). This scheme would usually also come with a sort-of factory function for the Child objects and a private access on the Child's constructor granting friendship to the parent or static factory function. That way, it is also possible to prohibit a programmer from creating instances of Child that are not directly owned by the parent to which they are attached. Note also, that move-semantics and/or deep-copying can make the parent "copyable" or at least movable while keeping the children consistent with their parent.
vector.push_back() passes arguments by reference, so at the end of the family function, p.children just contains references to the local variables, right?
No, vector takes arguments by const reference, then possibly allocates additional storage for that object, and then places a copy of the argument into that new memory slot (placement new operator). So the p.children are objects (not references) and are contained in the vector (it is called a "container" after all).
Why is it all working? In main, why can I access the parent and each of its children? Is it all because the local variables from family are still intact and haven't been overwritten by some subsequent function call?
If you read my first answer, it becomes evident why this still works (but it might not work all the time).
Related
class foo{
vector<foo*>* queue;
vector<int> pos;
foo(vector<foo*>* queue, vector<int> pos){
this->queue=queue;
this->pos=pos;
}
public:
foo(vector<foo*>* queue){
this->queue=queue;
}
void init(){
vector<int> posNew = pos;
//Create Binary Tree Children of the state FOO
posNew.push_back(/* An Additional Value*/)
foo newFoo(queue, posNew);
queue->push_back(&newFoo);
}//Here the variables newFoo and posNew are out of scope so they are deleted even from the queue
}
class bar{
vector<foo*> queue; //Assume that queue has a root node added to it.
bar(){
for(unsigned int i=0; i<queue.size();i++){
queue[i]->init();// Somewhere along when the third element is calculated the value overflows since I assume the object are deleted
}
}
}
I am trying to use BFS search with a queue to solve a problem. However I am not able to get the queue to work since the object child object I create are going out of scope. Any help of this would be appreciated.
EDIT:
In my actual code, I am having trouble since when the object goes out of scope it shows me these memory allocations.
This green part is where the root node is, the red part is where the expected data for the child nodes was supposed to be but its now deleted.
The variable queue is a vector of foo pointers, not foo objects. But in init(), you are declaring newFoo as a foo object and pushing it in the queue. newFoo is a local variable of function init(), so when the function finishes execution, newFoo is lost.
You can declare newFoo as a pointer and allocate memory for it, like
foo *newFoo = new foo(queue, posNew);
and push newFoo in your queue.
There are two meanings of "out of scope":
Through a function call, you jump to part of the program outside the lexical scope of the identifier. The object exists, but cannot be directly named. Indirection (pointer or reference) may be able to reach the object.
For objects with automatic lifetime, when the end of the scope is reached, the object is destroyed. There is no way to access the object after this point, because it no longer exists.
As 0605002 suggests, one way to avoid case #2 is to use lifetime other than automatic -- his answer shows an example of dynamic lifetime, but static lifetime is also possible, and data members also have lifetime that outlasts a single function call.
For your queue, dynamic lifetime managed by a smart pointer (std::unique_ptr or std::shared_ptr) would be a good choice.
I have a class that is responsible for creating and initializing a number of large objects, as the objects are all of the same Type and I don't want to repeat the same initializing code for all the objects, I call an Init method for each object, for example:
InitObject(objMember);
void Test::InitObject(LargeObject * obj)
{
obj = new LargeObject;
obj->Load();
obj->SetSomeProperty(false);
}
Once this has been done, from a public method I call a set of methods to get a pointer to each of the objects:
//public
LargeObject * Test::GetObject()
{
return objMember;
}
The issue is that the objects are losing scope, when InitObject is called, the objects are correctly constructed and populated, but when I call GetObject, it has lost everything.
I'm probably missing something trivial, but I can't see why it's going out of scope.
It is trivial, yes. You're initializing a copy of the original pointer. You probably want to pass it by reference:
void Test::InitObject(LargeObject*& obj)
Passing by value means that you're assigning the return of new to a copy of the pointer. The one outside the function InitObject remains unchanged.
A few more things - initializing objects after construction should be done with care. If the object isn't valid after construction, it's a bad design (excluding some rare cases). You can signal invalid initialization by throwing an exception from the constructor.
Also, consider using smart pointers instead of raw pointers.
This is one topic that is not making sense to me. Pointers to data members of a class can be declared and used. However,
What is the logic that supports the idea ? [I am not talking about the syntax, but the logic of this feature]
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time. Also, new objects may be created and destroyed during runtime. Hence, in effect, a single statement will cause a large number of allocations/deallocations. This seems rather counter-intuitive as compared to the rest of the language. Or is my understanding of this incorrect ? I dont think there is any other single initialization statement that will implicitly affect program execution as widely as this.
Lastly, how is memory allocated to these pointers ? Where are they placed with respect to objects ? Is it possible to see physical memory addresses of these pointers ?
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No, it does not. A pointer to a member is a special object that is very different from a pointer; it is a lot more similar to an offset. Given a pointer to an object of the class and a member pointer, you'd be able to get the value of a member; without the pointer to an object of a class a pointer to a member is useless.
Questions 2 and 3 stem from the same basic misunderstanding.
A single declaration of a pointer to a data member, creates pointers for every object of that class.
No. It creates a pointer to a member (which can be though of as an offset from the base of object)
You can then use it with a pointer to an object to get that member.
struct S
{
int x;
int y;
};
int S::* ptrToMember = &S::x; // Pointer to a member.
S obj;
int* ptrToData = &obj.x; // Pointer to object
// that happens to be a member
Notice in creating the pointer to a member we don't use an object (we just use the type information). So this pointer is an offset into the class to get a specific member.
You can access the data member via a pointer or object.
(obj.*ptrToMember) = 5; // Assign via pointer to member (requires an object)
*ptrToData = 6; // Assign via pointer already points at object.
Why does this happen as opposed to a single pointer being created to point to only one specific instance of the class ?
That is called a pointer.
A similar but parallel concept (see above).
What is the logic that supports the idea ?
Silly example:
void addOneToMember(S& obj, int S::* member) { (obj.*member) += 1; }
void addOneToX(S& obj) { addOneToMember(obj, &Obj::x);}
void addOneToY(S& obj) { addOneToMember(obj, &Obj::y);}
Also,if i understand this correctly, this would imply an indefinite/variable amount of memory being allocated at the pointer initialization as any number of objects may exist at that time.
No. Because a pointer to a member is just an offset into an object. You still need the actual object to get the value.
Lastly, how is memory allocated to these pointers ?
Same way as other objects. There is nothing special about them in terms of layout.
But the actual layout is implementation defined. So there is no way of answering this question without referring to the compiler. But it is really of no use to you.
Is it possible to see physical memory addresses of these pointers ?
Sure. They are just like other objects.
// Not that this will provide anything meaningful.
std::cout.write(reinterpret_cast<char*>(&ptrToMember), sizeof(ptrToMember));
// 1) take the address of the pointer to member.
// 2) cast to char* as required by write.
// 3) pass the size of the pointer to member
// and you should write the values printed out.
// Note the values may be non printable but I am sure you can work with that
// Also note the meaning is not useful to you as it is compiler dependent.
Internally, for a class that does not have virtual bases, a pointer-to-member-data just has to hold the offset of the data member from the start of an object of that type. With virtual bases it's a bit more complicated, because the location of the virtual base can change, depending on the type of the most-derived object. Regardless, there's a small amount of data involved, and when you dereference the pointer-to-data-member the compiler generates appropriate code to access it.
The problem I am having is that when my class CLimb runs its destructor, if member *parent is NULL I get an "Access violation writing location 0xcccccccc" error, after the destructor is called, but before the body is executed.
limb.h
class CLimb
{
public:
CLimb(void);
CLimb(CLimb *_parent);
~CLimb(void);
float cut;
float bone;
float resistance;
CLimb *parent;
};
limb.cpp
#include "limb.h"
CLimb::CLimb(void) :
cut(0),
bone(0),
resistance(0)
{
parent = NULL;
}
CLimb::CLimb(CLimb *_parent) :
cut(0),
bone(0),
resistance(0)
{
parent = _parent;
}
CLimb::~CLimb(void)
{
}
I was also wondering if I had 2 instances, limb01 and limb02, where limb02 is the parent of limb01, if limb02 is deleted limb01->parent now points to an incorrect address. How would I resolve this? Would I have to add a *child pointer as well?
Smart pointers are a solution. In particular, you can use a weak pointer here. A weak pointer is automatically reset when the reference count of the pointed-to object drops to zero (i.e. when it's deleted).
I assume your problem is that you are accessing the pointer after deleting it. So you need to keep track of which pointers point to valid objects, and which to dead ones.
There are several ways to resolve such problems more or less automatically.
A popular one would be using some kind of smart pointers, for example, shared_ptr. This would ensure that an object won't be deleted if there are still references to it.
Another approach is to establish a hierarchy: make each parent control the lifetime of its children. This means that (1) the children need to be deleted in the parent's destructor, and (2) no one except the parent should keep a pointer to a child (at least, for a long time).
Yet another popular approach would be using garbage collection, but I wouldn't recommend it in non-managed environments.
I have objects which create other child objects within their constructors, passing 'this' so the child can save a pointer back to its parent. I use boost::shared_ptr extensively in my programming as a safer alternative to std::auto_ptr or raw pointers. So the child would have code such as shared_ptr<Parent>, and boost provides the shared_from_this() method which the parent can give to the child.
My problem is that shared_from_this() cannot be used in a constructor, which isn't really a crime because 'this' should not be used in a constructor anyways unless you know what you're doing and don't mind the limitations.
Google's C++ Style Guide states that constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method. This solves the 'this-in-constructor' problem as well as a few others as well.
What bothers me is that people using your code now must remember to call Init() every time they construct one of your objects. The only way I can think of to enforce this is by having an assertion that Init() has already been called at the top of every member function, but this is tedious to write and cumbersome to execute.
Are there any idioms out there that solve this problem at any step along the way?
Use a factory method to 2-phase construct & initialize your class, and then make the ctor & Init() function private. Then there's no way to create your object incorrectly. Just remember to keep the destructor public and to use a smart pointer:
#include <memory>
class BigObject
{
public:
static std::tr1::shared_ptr<BigObject> Create(int someParam)
{
std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
ret->Init();
return ret;
}
private:
bool Init()
{
// do something to init
return true;
}
BigObject(int para)
{
}
BigObject() {}
};
int main()
{
std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
return 0;
}
EDIT:
If you want to object to live on the stack, you can use a variant of the above pattern. As written this will create a temporary and use the copy ctor:
#include <memory>
class StackObject
{
public:
StackObject(const StackObject& rhs)
: n_(rhs.n_)
{
}
static StackObject Create(int val)
{
StackObject ret(val);
ret.Init();
return ret;
}
private:
int n_;
StackObject(int n = 0) : n_(n) {};
bool Init() { return true; }
};
int main()
{
StackObject sObj = StackObject::Create(42);
return 0;
}
Google's C++ programming guidelines have been criticized here and elsewhere again and again. And rightly so.
I use two-phase initialization only ever if it's hidden behind a wrapping class. If manually calling initialization functions would work, we'd still be programming in C and C++ with its constructors would never have been invented.
Depending on the situation, this may be a case where shared pointers don't add anything. They should be used anytime lifetime management is an issue. If the child objects lifetime is guaranteed to be shorter than that of the parent, I don't see a problem with using raw pointers. For instance, if the parent creates and deletes the child objects (and no one else does), there is no question over who should delete the child objects.
KeithB has a really good point that I would like to extend (in a sense that is not related to the question, but that will not fit in a comment):
In the specific case of the relation of an object with its subobjects the lifetimes are guaranteed: the parent object will always outlive the child object. In this case the child (member) object does not share the ownership of the parent (containing) object, and a shared_ptr should not be used. It should not be used for semantic reasons (no shared ownership at all) nor for practical reasons: you can introduce all sorts of problems: memory leaks and incorrect deletions.
To ease discussion I will use P to refer to the parent object and C to refer to the child or contained object.
If P lifetime is externally handled with a shared_ptr, then adding another shared_ptr in C to refer to P will have the effect of creating a cycle. Once you have a cycle in memory managed by reference counting you most probably have a memory leak: when the last external shared_ptr that refers to P goes out of scope, the pointer in C is still alive, so the reference count for P does not reach 0 and the object is not released, even if it is no longer accessible.
If P is handled by a different pointer then when the pointer gets deleted it will call the P destructor, that will cascade into calling the C destructor. The reference count for P in the shared_ptr that C has will reach 0 and it will trigger a double deletion.
If P has automatic storage duration, when it's destructor gets called (the object goes out of scope or the containing object destructor is called) then the shared_ptr will trigger the deletion of a block of memory that was not new-ed.
The common solution is breaking cycles with weak_ptrs, so that the child object would not keep a shared_ptr to the parent, but rather a weak_ptr. At this stage the problem is the same: to create a weak_ptr the object must already be managed by a shared_ptr, which during construction cannot happen.
Consider using either a raw pointer (handling ownership of a resource through a pointer is unsafe, but here ownership is handled externally so that is not an issue) or even a reference (which also is telling other programmers that you trust the referred object P to outlive the referring object C)
A object that requires complex construction sounds like a job for a factory.
Define an interface or an abstract class, one that cannot be constructed, plus a free-function that, possibly with parameters, returns a pointer to the interface, but behinds the scenes takes care of the complexity.
You have to think of design in terms of what the end user of your class has to do.
Do you really need to use the shared_ptr in this case? Can the child just have a pointer? After all, it's the child object, so it's owned by the parent, so couldn't it just have a normal pointer to it's parent?