views:

157

answers:

6

I am coming from a C# background to C++. Say I have a method that creates a object in a method on the stack, then I pass it to another classes method which adds it to a memeber vector.

void DoStuff()
{
    SimpleObj so = SimpleObj("Data", 4);
    memobj.Add(so); 
}

//In memobj
void Add(SimpleObj& so)
{
   memVec.push_back(so); //boost::ptr_vector object
}

Here are my questions:

  1. Once the DoStuff methods ends will the so go out of scope and be popped from the stack?
  2. memVec has a pointer to so but it got popped what happens here?
  3. Whats the correct way to pass stack objects to methods that will store them as pointers?

I realise these are probably obvious to a C++ programmer with some expereince.

Mark

+3  A: 

To achieve your goal, you should use a shared_ptr:

void DoStuff()
{
    boost::shared_ptr<SimpleObj> so(new SimpleObj("Data", 4));
    memobj.Add(so); 
}

//In memobj
void Add(boost::shared_ptr<SimpleObj> so)
{
   memVec.push_back(so); // std::vector<boost::shared_ptr<SimpleObj> > memVec;
}
Space_C0wb0y
Ok that makes sense, so the reference count will be one on the ptr once added to the vector, then it wont be destroyed.
Mark
@Mark: Yes. And when the container gets destroyed, the reference count for each `shared_ptr` in the container will get decreased by one (and the objects will be deleted on the spot if it reaches 0).
Space_C0wb0y
I'd recommend `unique_ptr` instead of `shared_ptr` if you're using C++0x - there's less overhead. Instead of making copies which increase the reference count, it just gets moved around.
AshleysBrain
You have to be careful using `unique_ptr` to avoid accidentally moving out of the container, leaving a NULL pointer behind. Use `shared_ptr` unless you really know what you're doing.
Anthony Williams
+8  A: 
  1. Yes.
  2. The pointer remains "alive", but points to a no-longer-existent object. This means that the first time you try to dereference such pointer you'll go in undefined behavior (likely your program will crash, or, worse, will continue to run giving "strange" results).
  3. You simply don't do that if you want to keep them after the function returned. That's why heap allocation and containers which store copies of objects are used.

The simplest way to achieve what you are trying to do would be to store a copy of the objects in a normal STL container (e.g. std::vector). If such objects are heavyweight and costly to copy around, you may want to allocate them on the heap store them in a container of adequate smart pointers, e.g. boost::shared_ptr (see the example in @Space_C0wb0y's answer).

Another possibility is to use the boost::ptr_vector in association with boost::ptr_vector_owner; this last class takes care of "owning" the objects stored in the associated ptr_vector, and deleting all the pointers when it goes out of scope. For more information on ptr_vector and ptr_vector_owner, you may want to have a look at this article.

Matteo Italia
Thanks, I want to avoid copying objects around, but also avoid having to manage memory on the heap, so I think I'll look at the last two options.
Mark
Since you come from C#, I recommend you to have a look also at the other smart pointers provided by boost and learn where each of them is better used. Memory management in C++ isn't as easy as in C#, but using the right smart pointers it becomes almost automatic. BTW, if my answer or another one solved your problem, you may consider marking it as "accepted".
Matteo Italia
Yeah I am making use of Boost lib, and the smart pointer, just didnt understand them fully, but you have enlightented me, thanks.
Mark
In C++0x I'd recommend `std::vector<std::unique_ptr<T>>`, which is an exception-safe, low-overhead, automatically memory-managing container that probably does everything you want, and better than boost::ptr_vector (which IIRC doesn't work with some STL algorithms).
AshleysBrain
Yes, the new move semantics makes it possible to write smart pointers that work better in several situations (especially in STL containers). I'd upvote your comment if I had votes left. :)
Matteo Italia
@Ashley: I am developing on Linux Fedora 13, so ill need to check if the that includes C++0x
Mark
GCC has support for it so Ill give that a go, thanks
Mark
Well, it hasn't, but the major compilers have a good level of support for several of its new features (see e.g. http://wiki.apache.org/stdcxx/C++0xCompilerSupport). g++ in particular is quite well-placed in this respect; however, keep in mind that at the moment the g++ version normally distributed is the 4.4. You can see what's your by typing g++ --version in a terminal.
Matteo Italia
Yeah I did some digging after that post. Seems like GCC has the unique_ptr
Mark
So I can create a unique_ptr of SimpleObj in DoStuff, pass it to Add and then add it to a std:vector there?
Mark
I think you can do that way, but I'm not perfectly familiar with the new C++0x move semantics, so it's better if someone else explains you what's going on under the hood :) . In the meantime, for some examples have a look at this: http://www.devx.com/cplus/10MinuteSolution/39071/1954
Matteo Italia
I see from another answer (below) AshleysBrain has answered that.
Mark
Are you talking about @Space_C0wb0y's answer? That uses boost::shared_ptr, which works in a different way (reference counting vs move semantics), even if the syntax should be identical. I don't see examples with std::unique_ptr in other answers (apart from the references to it by @AshleysBrain).
Matteo Italia
I think his anwser shows the code I need to implement my solution, im not sure how I could use ptr_vector_owner to solve my problem without going through the links you provide.
Mark
A: 

In order to store a pointer to an object it must be created with new. Otherwise it will disappear when going out of scope.
The easiest solution to your problem as presented here would be to use std::vector instead of boost::ptr_vector, because this way the push_back would copy the object in the vector

stefaanv
+1  A: 

Yes your so object will be popped off the stack once your function leaves scope. You should create a heap object using new and add a pointer to that in your vector.

As said before, the pointer in your vector will point to something undefined once your first function goes out of scope

Tony
+1  A: 

That code won't compile because inside the Add function you're trying to trying to push a whole object into a vector that expects a pointer to an object.

If instead you were to take the address of that object and push that onto the vector, then it would be dangerous as the original object would soon be popped off the stack and the pointer you stored would be pointing to uninitialised memory.

If you were using a normal vector instead of a pointer vector then the push_back call would be copying the whole object rather than the pointer and thus it would be safe. However, this is not necessarily efficient, and the 'copy everything' approach is probably not intuitive to someone from the C#, Java, or Python worlds.

Kylotan
A: 

1.Once the DoStuff methods ends will the so go out of scope and be popped from the stack? Yes. so is a local variable created on the stack and so will be popped once the function execution is complete.

2.memVec has a pointer to so but it got popped what happens here? memVec only points to the addres location where so was placed, but the contents of that memory location were lost when function eeccution was complete and all variables local to that function were popped from the stack.

3.Whats the correct way to pass stack objects to methods that will store them as pointers? Create the so object on heap using dynamic memory allocation(new/malloc) and then pass that pointer to another method which needs to store that so.

Als