Pointers and params

Started by
5 comments, last by the_edd 16 years, 7 months ago
Hi folks!! what is better/safety/elegant/memory frendly using pointers this one

void f(void* param){
.......
}

void main(){

Pirulo* p = new Pirulo(); // the class is defined in other file

f(p);

delete p;

}

or this one

void f(void& param){ // Meyers recomend const void& param
.......
}

void main(){

Pirulo p; // the class is defined in other file

f(p);



}

thanks in advance
Advertisement
Well in one case you're allocating on the stack, another you're allocating on the heap.

As far as the functions go, don't use void pointers.
Use new and delete when the lifetime of the object type you're creating must exceed the preceeding '{' brace and the proceeding '}' brace, otherwise (and in your case) if the object need only exist between the two braces then use the second method.

Using void pointers/references is normally a bad design choice.
What's wrong with:
void f(Pirulo& param) {
// ....
}

If you use void you can pass anything in as a parameter and your function has no way to know what that something actually was; so it can't actually do much with it unless it was just the address it was interested in (which is not normally the case).
The problem with the OP is that it is mixing multiple choices into 1 question AND asking for us to say what is "better" without a context.

As for "safer" the short answer in C++ is always the choice that requires the least thought to use properly, or provides the minimum set of features - IF it does what you need at the moment.

Key to remember is that C++ doesn't have a single facility not useful and needed in some case (except a few things who's only need is backwards compatibility - and the stupid keyword "auto").

So what you need to be looking for is wisdom / experience is what the reasons for features are and how they might be used and their true meanings and consequences, so you judge which would be appropriate for various needs.

dmatter's post explained the scope aspect of heap vs. stack memory very simply and well.

As for the * vs. & question, it depends. If there was no history or idiom, the & version would be the natural choice when you do not want to support the "null" case. Whereas the * version is the ONLY option when you do need to support passing a null. The third choice - const & is the preferred choice for any situation where is applies.

1. Prefer const when you should not be modifying an object in a method. Note I said "should not", not "are not". Sometimes you "are not" modifying the variable in THIS version of the method, but will be in another. In that case const doesn't make sense. A function signature is a contract and you should use const if you are PROMISING not to modify an object.

2. Prefer & to *. There are 2 cases I can think of right now that use * instead of &: 1) when you are going to point to different things (for instance if you are looping though items than a current * often makes more sense than a current & because the & couldn't be changed to point to a different object) 2) When you want to support the null case. If those don't apply, use &.
thnaks to all for your answers!! i have another question ... what about the memomry-foot-print-friendly and * vs $ any suggestio,same tips?
thnaks a lot!
[/source]template<typename T>
void f(T& param)
{
....
}

// void main() is not standard compliant C++.
int main()
{
Pirula p;
f(p);
}
Quote:Original post by XaiKey to remember is that C++ doesn't have a single facility not useful and needed in some case (except a few things who's only need is backwards compatibility - and the stupid keyword "auto").


Actually, "auto" is probably going to be made useful again in the next revision of the C++ standard.

for (std::map<string, double>::const_iterator b = m.begin(), m.end(); b != e; ++b){}// becomesfor (auto b = m.begin(), e = m.end(); b != e; ++b){}// (though I think a foreach construct is being considered, also)


To the O.P:

A good rule of thumb is this: Make sure that the lifetime of every object you create is handled by the program and not by the programmer. This is what happens when you create objects on the "stack", in automatic storage, as in your second code snippet.

In general, if you're having to write delete explicitly, you're doing something wrong, or at least you're causing problems for yourself.

Always prefer to handle resources such as pointers to dynamically allocated objects with a wrapper class e.g.

boost::shared_ptr<Pirulo> p(new Pirulo());// no need to delete explicitly


Pointers don't have destructors, so they don't know to delete what they point to. By wrapping a pointer to a dynamically allocated object in something such as boost::shared_ptr<>, we are effectively giving it a destructor, which knows when and how to clean up after itself.

But surely one manual new/delete pair isn't so bad? Well, it isn't at the moment. But if you add extra return statements before the delete is invoked, you will have to remember to delete the pointer again, just before each return statement.

Similarly, if any function call made between the time you new and delete your object can throw an exception, you will have a memory leak unless you explicitly add try/catch blocks around those functions. If the function f() in your example throws an exception, you'd leak memory and any other resources associated with a Pirulo object. Even if you know that f() won't throw now, there's no reason that you won't change it at some point in future in such a way that it may release an exception.

Adding all the extra delete statements and try/catch scaffolding can become a real PITA and obfuscates the code no end. I wrote about this in more detail, here.

The simplest way of all to handle objects, of course, is to create them on the stack (as in your second chunk of code) and give them value semantics. Then the object destructors will do the right thing, even in the face of early-returns and exceptions, relieving the programmer of the burden.

The C++ standard containers expect value semantics of your objects, so its a good thing to strive for.

By the way, you can't have a reference-to-void, so Meyers can't have recommended it. Meyers recommends doing what I've just spelled out;

1. Creating objects with value semantics, where possible (look up "the rule of three").
2. Putting objects that are unable to clean up after themselves in a wrapper object that will be able to do that for them.

This topic is closed to new replies.

Advertisement