I’ve been working on a school assignment that makes pretty heavy use of vectors, sets, stacks and queues.
What is the difference between Foo and Bar, especially when passing Foo and Bar between functions? When would it be safe to call delete on Bar, if ever? I’m guess it’s never safe to call delete on Bar unless everything in that vector has been moved? If I return Foo, wont it (and its contents) be deleted when the function exits?
vector<Line *> Foo;
and:
vector<Line *> * Bar = new vector<Line *>();
Similary, lets say I have a function:
vector<Line *> BSTIndex::query(string expression)
{
vector<Line *> result; //Holds the lines that match the expression
string query = expression;
queue<string> * output = expressionParser(query);
doSomeStuffWithOutputHere();
return result;
}
And my expressionParser is:
queue<string> * BSTIndex::expressionParser(string query)
{
char * cQuery = new char[100];
strcpy_s(cQuery, 100,query.c_str());
//strcpy(cQuery, query.c_str());
queue<string> * output = new queue<string>(); //Operators go in the queue
stack<string> * s = new stack<string>(); //Operands go on the stack
performSomeMagicOnQueueAndStackHere();
return output;
}
The stack is actually only local to expressionParser so I KNOW I can remove the new keyword from that. The queue however, needs to go back to the query function where it’s used but then that’s it. Do I HAVE To create a pointer to the queue in this case (I want to say yes because it’s going to fall out of scope when expressionParser returns). If I need to create the pointer, then I should call a delete output in my query function to properly get rid of the queue?
My last concern is the vector being returned by query. Should that be left as I have it or should it be a pointer and what’s the difference between them? Once I consume that vector (display the information in it) I need it to be removed from memory, however, the pointers contained in the vector are still good and the items being pointed to by them should not be deleted. What’s the best approach in this case?
What happens to the contents of containers when you call delete on the container? If the container held pointers, and those pointers are deleted won’t that affect other areas of my program?
SO many questions (direct and indirect) crammed into such a small space!
Foois an object of automatic (potentially static (but the distinction is not important here)) storage duration. This means it is created at the point of declaration (constructors called) and destroyed when it goes out of scope (destructors called).Baron the other hand is a pointer. Pointer have no constructors or destructors and are used topointat other objects (or NULL). HereBaris initialized to point at an object of dynamic storage duration. This is an object that has to be manually released (otherwise it will leak).When passing
Foo(by value) to/from functions the copy constructor is used to make a copy of the original object. Note: The standard explicitly states that copying from a function (via return) can be elided (look up RVO/NRVO) and all modern compilers will remove the extra copy construction and build in place at the return site (but this is an optimization invisible to the user just think of it as a very efficient copy out of a function). The resut of this is that when passed into a function (by value) or returned from a function (by return) you are working on a new object (not the original). This is important because of the side effects of using the object will not affect the original. (see your question below about returningFoo).When passing
Bar(by value) the pointer is copied. But this means that what is pointed at is the same. So modifying an object via the pointer is modifying the original value. This makes passing it as a parameter very cheap (because all you are passing is the address of the object). But it makes returning a value potentially dangerous, this is because you could return the address of an object that has gone out of scope inside the function.Using pointers in inherently dangerous and modern C++ programs rarely use RAW pointers directly. Pointers are usually wrapped up inside objects that manage the ownership and potentially lifespan of the object (see smart pointers and containers).
It is only safe to delete
Barif:It would safe to delete
Bareven if it’s content had not been moved (though you could leak if the contained pointers were owned byBar(this is not directly unsafe but can be inconvenient when you run out of space)). This is another reason pointers are rarely used directly, there are no ownership semantics associated with a pointer. This means we can not tell ifBarowns the pointers it holds (it is the responsibility of the owner to call delete on a pointer when it is no longer used).Yes. But because you return an object it will be copied out of the function. So what you use outside the function is a copy of
Foo(Though optimizers may elide the copy because of RVO/NRVO. Not if the copy is elided the destructor is also elided).Not only can you but you should. As currently you are leaking this object when it goes out of scope.
No. You can pass the obejct back by value. It will be correctly copied out of the function. If you find that this is expensive (unlikely) then you could create a dynamic object with new and pass it back as a pointer (but you may want to look at smart pointers). Remember that pointers do not indicate that you are the owner so it is unclear who should delete a pointer (or even if it should be deleted). So (if passing a value is too expensive) use a std::auto_ptr<> and pass the pointer back inside it.
Yes. And No. If you create a
dynamic objectwith new. Then somebody must call delete on it. It is bad C++ style to do this manually. Learn to use smart pointers so that it is done automatically and in an exception safe manor.I would do it like this:
Depends who owns the pointers.
If the content of the containers are pointers. Then nothing. The pointers disappear (what they point at is unchanged and unaffected). If the container contains objects (not pointers) then the destructor is called on the objects.
It would. But you would have to call delete manually.