简体   繁体   中英

Storing a pointer to an object created in a method

Using C++:

I currently have a method in which if an event occurs an object is created, and a pointer to that object is stored in a vector of pointers to objects of that class. However, since objects are destroyed once the local scope ends, does this mean that the pointer I stored to the object in the vector is now null or undefined? If so, are there any general ways to get around this - I'm assuming the best way would be to allocate on the heap.

I ask this because when I try to access the vector and do operations on the contents I am getting odd behavior, and I'm not sure if this could be the cause or if it's something totally unrelated.

It depends on how you allocate the object. If you allocate the object as an auto variable, (ie on the stack), then any pointer to that object will become invalid once the object goes out of scope, and so dereferencing the pointer will lead to undefined behavior.

For example:

Object* pointer;

{
  Object myobject;
  pointer = &myobject;
}

pointer->doSomething(); // <--- INVALID! myobject is now out of scope

If, however, you allocate the object on the Heap, using the new operator, then the object will remain valid even after you exit the local scope. However, remember that there is no automatic garbage collection in C++, and so you must remember to delete the object or you will have a memory leak.

So if I understand correctly you have described the following scenario:

class MyClass
{
public:
  int a;
  SomeOtherClass b;
};

void Test()
{
   std::vector<MyClass*> b;
   for (int i=0; i < 10; ++i)
   {
      MyClass b;
      v.push_back(&b);
   }
   // now v holds 10 items pointers to strange and scary places. 
} 

This is definitely bad. There are two primary alternatives:

  1. allocate the objects on the heap using new.
  2. make the vector hold instances of MyClass (ie std::vector<MyClass> )

I generally prefer the second option when possible. This is because I don't have to worry about manually deallocating memory, the vector does it for me. It is also often more efficient. The only problem, is that I would have to be sure to create a copy constructor for MyClass. That means a constructor of the form MyClass(const MyClass& other) { ... } .

If you store a pointer to an object, and that object is destroyed (eg goes out of scope), that pointer will not be null, but if you try to use it you will get undefined behavior. So if one of the pointers in your vector points to a stack-allocated object, and that object goes out of scope, that pointer will become impossible to use safely. In particular, there's no way to tell whether a pointer points to a valid object or not; you just have to write your program in such a way that pointers never ever ever point to destroyed objects.

To get around this, you can use new to allocate space for your object on the heap. Then it won't be destroyed until you delete it. However, this takes a little care to get right as you have to make sure that your object isn't destroyed too early (leaving another 'dangling pointer' problem like the one you have now) or too late (creating a memory leak).

To get around that , the common approach in C++ is to use what's called (with varying degrees of accuracy) a smart pointer. If you're new to C++ you probably shouldn't worry about these yet, but if you're feeling ambitious (or frustrated with memory corruption bugs), check out shared_ptr from the Boost library.

If you have a local variable, such as an int counter, then it will be out of scope when you exit the function, but, unless you have a C++ with a garbage collector, then your pointer will be in scope, as you have some global vector that points to your object, as long as you did a new for the pointer.

I haven't seen a situation where I have done new and my memory was freed without me doing anything.

To check (in no particular order):

  • Did you hit an exception during construction of member objects whose pointers you store?

  • Do you have a null-pointer in the container that you dereference?

  • Are you using the vector object after it goes out of scope? (Looks unlikely, but I still have to ask.)

  • Are you cleaning up properly?

Here's a sample to help you along:

void SomeClass::Erase(std::vector<YourType*> &a)
{
   for( size_t i = 0; i < a.size(); i++ ) delete a[i];
   a.clear();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM