Creating an object on the stack then passing by re

2019-04-28 19:00发布

问题:

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

回答1:

  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.



回答2:

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;
}


回答3:

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



回答4:

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.



回答5:

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