views:

154

answers:

3

I would like to add 2 elements to a vector<Node*> and then clear all the elements and release the memory.
Does this code do that in a right way?

#include <stdlib.h>
#include <iostream>
#include <vector>

using namespace std;

class Node {
public:
    int value;
    // ...and some other fields and methods...
};

int main(int argc, char** argv) {
    Node* n = new Node;
    n->value = 20;
    vector<Node*> v;
    v.push_back(n);
    n = new Node;
    n->value = 52;
    v.push_back(n);
    for (vector<Node*>::iterator i = v.begin(); i != v.end(); i++) {
        cout << (*i)->value << endl;
        delete *i;
        *i = NULL;
    }
    v.clear();
    return (EXIT_SUCCESS);
}
+8  A: 

It looks fine to me. There are a few things that I'd change (subjectively):

*i = NULL;  // This is unnecessary.

Then I'd avoid reusing n (actually, I'd avoid it entirely):

v.push_back(new Node);
v.back()->value = 20;
v.push_back(new Node);
v.back()->value = 52;

Also, you may want to consider smart pointers to track your memory for you. See shared_ptr and ptr_vector.

Stephen
Why use smart pointers when there does not seem to be any "multiple ownersihps" over the data?
Simon
@Simon : Smart pointers (in general) aren't only useful when there is multiple ownership - so I assume you're referring to use of `shared_ptr`? You cannot put an `auto_ptr` in a standard container, but you can put a `shared_ptr` in a container ( http://www.gotw.ca/publications/using_auto_ptr_effectively.htm ). Some people avoid raw ptrs at all costs, I'm not suggesting that - just be aware that there are solutions that allow you to avoid the memory cleanup; and that @Jani should make the decision of when to use it on his/her own.
Stephen
If you have a clear ownership, shared_ptr provides a costly memory cleanup (in cycles) while also increasing the link-time if you're not already using boost. Shouldn't scoped-pointer be a much better recommendation in situations where you have an object that is the owner of other objects?
Simon
@Simon : I don't disagree that `shared_ptr` is heavy on resources. Do you have an implementation of `scoped_ptr` in mind? AFAIK, Boost's is noncopyable, so it can't be put in containers. Using `shared_ptr` in this case is a fairly common solution to that problem.
Stephen
@Stephen: I guess that scoped-array would be the correct choice when it comes to terms of boost. I'll get back to you regarding a scoped pointer that's copyable.
Simon
@Stephen: This is what I could throw together in a couple of minutes on the train: http://www.copypastecode.com/33216/. I noticed that I forgot to add appropriate accessor's for the pointer. Not to mention that the bool could probably be baked into the last bit of the pointer and simply not allow pointers that aren't 2-byte aligned.
Simon
@Simon : Well, `scoped_array` is for storing dynamically allocated array (analogous to a `scoped_ptr`). It's basically a `T[]` on the heap, which is not the same thing as a `vector<T*>`. The best solution to storing a `vector<T*>` that's memory managed is `ptr_vector` (as I mentioned in the answer).
Stephen
@Simon : Regarding your implementation, all subsequent copies of a pointer will have invalid references when the original copy is destroyed. Imagine: `void foo() { vector<CScopedPtr<int> > v(1); if (1) { CScopedPtr p(new int); v.back() = p; } /* closing the 'if' scope destroys p, destroying the int, but 'v' still has a weak copy. */ cout << *v[0]; /* will segfault */ }`
Stephen
@Stephen: Yes but once the array goes out of scope, all data there is deleted - correct? Which is what "memory management" would be in the context of a scope. In this specific case (the code he wrote) it would be the scope of the main function. There's always a scope that a memory allocation can be contained within. Yes, accessing a pointer that's deleted will cause a segfault (unless you have your own memory allocator). That's the idea of a scoped-pointer is that once it goes out of scope it gets deleted. In other words, you can't give it away outside of the scope.
Simon
@Simon : Sorry, I don't know what point you're trying to make anymore. One one hand, you want to change the requirements of the OP's question (storing dynamically allocated objects in a vector), on the other, you seem to be arguing in favor of a broken implementation of `scoped_ptr`.
Stephen
I'm not trying to argue in the favor of the broken implementation of scoped_ptr, I'm trying to say that accessing memory outside of a scope that it's not defined in gives you exactly that result - undefined (in this case, segfault).
Simon
@Simon : that's true (I don't think I said anything to the contrary). Although, the pedant in me wants to be explicit in that "memory" doesn't have a scope. It does have a lifetime between `new` and `delete`. RAII classes bind that lifetime to a scope.
Stephen
+5  A: 

That will do what you expect. However, clear() is totally unnecessary since the vector will be destroyed right after that when you leave the current scope (which also happens to be the end of the function and the end of the program in this case). If you were planning on keeping the vector around to do more with it, then clear() would remove all of the pointers from the vector. As it is, the vector is being destroyed right after, so there's no point in calling clear().

Also, the nitpicker in me wants to say that you should use ++i in your loop instead of i++ since i++ creates a temporary that the compiler can't optimize away (since you're dealing with an overloaded operator). Also, since you're just going to destroy the vector right after deleting everything in it, there's not much point in setting all of it's elements to NULL. If you were going to re-use the elements rather than clear or destroy the vector, then that would be a good idea. But in this case, it's just inefficient.

Jonathan M Davis
+3  A: 

Yes that works.

Some remarks :

  • Instead of including stdlib.h, the c++ equivalent is cstdlib.
  • Your vector could be vector<Node> if you don't really need pointers; and it would be better to use smart pointers if you need them.
Scharron