Reputation: 19873
Suppose that I define some class:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
}
Then write some code using it. Why would I do the following?
Pixel p;
p.x = 2;
p.y = 5;
Coming from a Java world I always write:
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
They basically do the same thing, right? One is on the stack while the other is on the heap, so I'll have to delete it later on. Is there any fundamental difference between the two? Why should I prefer one over the other?
Upvotes: 78
Views: 15506
Reputation: 5965
Why not use pointers for everything?
They're slower.
Compiler optimizations will not be as effective with pointer access symantics, you can read up about it in any number of web sites, but here's a decent pdf from Intel.
Check pages, 13,14,17,28,32,36;
Detecting unnecessary memory references in the loop notation:
for (i = j + 1; i <= *n; ++i) {
X(i) -= temp * AP(k); }
The notation for the loop boundaries contains the pointer or memory reference. The compiler does not have any means to predict whether the value referenced by pointer n is being changed with loop iterations by some other assignment. This uses the loop to reload the value referenced by n for each iteration. The code generator engine also may deny scheduling a software pipelined loop when potential pointer aliasing is found. Since the value referenced by pointer n is not anging within the loop and it is invariant to the loop index, the loading of *n s to be carried outside of the loop boundaries for simpler scheduling and pointer disambiguation.
... a number of variations on this theme....
Complex memory references. Or in other words, analyzing references such as complex pointer computations, strain the ability of compilers to generate efficient code. Places in the code where the compiler or the hardware is performing a complex computation in order to determine where the data resides, should be the focus of attention. Pointer aliasing and code simplification assist the compiler in recognizing memory access patterns, allowing the compiler to overlap memory access with data manipulation. Reducing unnecessary memory references may expose to the compiler the ability to pipeline the software. Many other data location properties, such as aliasing or alignment, can be easily recognized if memory reference computations are kept simple. Use of strength reduction or inductive methods to simplify memory references is crucial to assisting the compiler.
Upvotes: 2
Reputation: 71110
The code:
Pixel p;
p.x = 2;
p.y = 5;
does no dynamic allocation of memory - there is no searching for free memory, no updating of memory usage, nothing. It is totally free. The compiler reserves space on the stack for the variable at compile time - it works out have much space to reserve and creates a single opcode to move the stack pointer the required amount.
Using new requires all that memory management overhead.
The question then becomes - do you want to use stack space or heap space for your data. Stack (or local) variables like 'p' require no dereferencing whereas using new adds a layer of indirection.
Upvotes: 11
Reputation: 248209
Yes, one is on the stack, the other on the heap. There are two important differences:
delete
yourself, instead wrapping it in stack-allocated objects which call delete
internally, typicaly in their destructor. If you attempt to manually keep track of all allocations, and call delete
at the right times, I guarantee you that you'll have at least a memory leak per 100 lines of code.As a small example, consider this code:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
};
void foo() {
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
bar();
delete p;
}
Pretty innocent code, right? We create a pixel, then we call some unrelated function, and then we delete the pixel. Is there a memory leak?
And the answer is "possibly". What happens if bar
throws an exception? delete
never gets called, the pixel is never deleted, and we leak memory. Now consider this:
void foo() {
Pixel p;
p.x = 2;
p.y = 5;
bar();
}
This won't leak memory. Of course in this simple case, everything is on the stack, so it gets cleaned up automatically, but even if the Pixel
class had made a dynamic allocation internally, that wouldn't leak either. The Pixel
class would simply be given a destructor that deletes it, and this destructor would be called no matter how we leave the foo
function. Even if we leave it because bar
threw an exception. The following, slightly contrived example shows this:
class Pixel {
public:
Pixel(){ x=new int(0); y=new int(0);};
int* x;
int* y;
~Pixel() {
delete x;
delete y;
}
};
void foo() {
Pixel p;
*p.x = 2;
*p.y = 5;
bar();
}
The Pixel class now internally allocates some heap memory, but its destructor takes care of cleaning it up, so when using the class, we don't have to worry about it. (I should probably mention that the last example here is simplified a lot, in order to show the general principle. If we were to actually use this class, it contains several possible errors too. If the allocation of y fails, x never gets freed, and if the Pixel gets copied, we end up with both instances trying to delete the same data. So take the final example here with a grain of salt. Real-world code is a bit trickier, but it shows the general idea)
Of course the same technique can be extended to other resources than memory allocations. For example it can be used to guarantee that files or database connections are closed after use, or that synchronization locks for your threading code are released.
Upvotes: 189
Reputation: 28893
That confused me a lot when I was a new C++ programmer (and it was my first language). There are a lot of very bad C++ tutorials that generally seem to fall into one of two categories: "C / C++" tutorials, which really means it's a C tutorial (possibly with classes), and C++ tutorials that think C++ is Java with delete.
I think it took me about 1 - 1.5 years (at least) to type "new" anywhere in my code. I used STL containers like vector frequently, which took care of that for me.
I think a lot of answers seem to either ignore or just avoid directly saying how to avoid this. You generally don't need to allocate with new in the constructor and clean up with delete in the destructor. Instead, you can just directly stick the object itself in the class (rather than a pointer to it) and initialize the object itself in the constructor. Then the default constructor does everything you need in most cases.
For almost any situation where this won't work (for instance, if you risk running out of stack space), you should probably be using one of the standard containers anyway: std::string, std::vector, and std::map are the three that I use most often, but std::deque and std::list are also quite common. The others (things like std::set and the non-standard rope) aren't used as much but behave similarly. They all allocate from the free store (C++ parlance for "the heap" in some other languages), see: C++ STL question: allocators
Upvotes: 1
Reputation: 8145
Logically they do the same thing -- except for cleanup. Just the example code you've written has a memory leak in the pointer case because that memory is not released.
Coming from a Java background, you may not be completely prepared for how much of C++ revolves around keeping track of what has been allocated and who is responsible for freeing it.
By using stack variables when appropriate, you don't have to worry about freeing that variable, it goes away with the stack frame.
Obviously, if you're super careful, you can always allocate on the heap and free manually, but part of good software engineering is to build things in such a way that they can't break, rather than trusting your super-human programmer-fu to never make a mistake.
Upvotes: 25
Reputation: 20037
The issue isn't pointers per se (aside from introducing NULL
pointers), but doing memory management by hand.
The funny part, of course, is that every Java tutorial I've seen has mentioned the garbage collector is such cool hotness because you don't have to remember to call delete
, when in practice C++ only requires delete
when you call new
(and delete[]
when you call new[]
).
Upvotes: 4
Reputation: 829
First case is best unless more members are added to Pixel class. As more and more member gets added, there is a possibility of stack overflow exception
Upvotes: -2
Reputation: 264649
They are not the same until you add the delete.
Your example is overly trivial, but the destructor may actually contain code that does some real work. This is referred to as RAII.
So add the delete. Make sure it happens even when exceptions are propagating.
Pixel* p = NULL; // Must do this. Otherwise new may throw and then
// you would be attempting to delete an invalid pointer.
try
{
p = new Pixel();
p->x = 2;
p->y = 5;
// Do Work
delete p;
}
catch(...)
{
delete p;
throw;
}
If you had picked something more interesting like a file (which is a resource that needs to be closed). Then do it correctly in Java with pointers you need to do this.
File file;
try
{
file = new File("Plop");
// Do work with file.
}
finally
{
try
{
file.close(); // Make sure the file handle is closed.
// Oherwise the resource will be leaked until
// eventual Garbage collection.
}
catch(Exception e) {};// Need the extra try catch to catch and discard
// Irrelevant exceptions.
// Note it is bad practice to allow exceptions to escape a finally block.
// If they do and there is already an exception propagating you loose the
// the original exception, which probably has more relevant information
// about the problem.
}
The same code in C++
std::fstream file("Plop");
// Do work with file.
// Destructor automatically closes file and discards irrelevant exceptions.
Though people mention the speed (because of finding/allocating memory on the heap). Personally this is not a deciding factor for me (the allocators are very quick and have been optimized for C++ usage of small objects that are constantly created/destroyed).
The main reason for me is object life time. A locally defined object has a very specific and well defined lifetime and the the destructor is guaranteed to be called at the end (and thus can have specific side effects). A pointer on the other hand controls a resource with a dynamic life span.
The concept of who owns the pointer. It is the responsibility of the owner to delete the object at the appropriate time. This is why you very rarely see raw pointers like that in real programs (as there is no ownership information associated with a raw pointer). Instead pointers are usually wrapped in smart pointers. The smart pointer defines the semantics of who owns the memory and thus who is responsible for cleaning it up.
Examples are:
std::auto_ptr<Pixel> p(new Pixel);
// An auto_ptr has move semantics.
// When you pass an auto_ptr to a method you are saying here take this. You own it.
// Delete it when you are finished. If the receiver takes ownership it usually saves
// it in another auto_ptr and the destructor does the actual dirty work of the delete.
// If the receiver does not take ownership it is usually deleted.
std::tr1::shared_ptr<Pixel> p(new Pixel); // aka boost::shared_ptr
// A shared ptr has shared ownership.
// This means it can have multiple owners each using the object simultaneously.
// As each owner finished with it the shared_ptr decrements the ref count and
// when it reaches zero the objects is destroyed.
boost::scoped_ptr<Pixel> p(new Pixel);
// Makes it act like a normal stack variable.
// Ownership is not transferable.
There are others.
Upvotes: 30
Reputation: 10820
Objects created on the stack are created faster than objects allocated.
Why?
Because allocating memory (with default memory manager) takes some time (to find some empty block or even allocate that block).
Also you don't have memory management problems as the stack object automatically destroys itself when out of scope.
The code is simpler when you don't use pointers. If your design allows you to use stack objects, I recommend that you do it.
I myself wouldn't complicate the problem using smart pointers.
OTOH I have worked a little in the embedded field and creating objects on the stack is not very smart (as the stack allocated for each task/thread is not very big - you must be careful).
So it's a matter of choice and restrictions, there is no response to fit them all.
And, as always don't forget to keep it simple, as much as possible.
Upvotes: 0
Reputation: 17047
Something that I haven't seen mentioned is the increased memory usage. Assuming 4 byte integers and pointers
Pixel p;
will use 8 bytes, and
Pixel* p = new Pixel();
will use 12 bytes, a 50% increase. It doesn't sound like a lot until you allocate enough for a 512x512 image. Then you are talking 2MB instead of 3MB. This is ignoring the overhead of managing the heap with all of these object on them.
Upvotes: 0
Reputation: 24561
The question is: why would you use pointers for everything? Stack allocated objects are not only safer and faster to create but there is even less typing and the code looks better.
Upvotes: 1
Reputation: 68074
Use pointers and dynamically allocated objects ONLY WHEN YOU MUST. Use statically allocated (global or stack) objects wherever possible.
To clarify, by 'static' in this context, I mean non-dynamically allocated. IOW, anything NOT on the heap. Yes, they can have object lifetime issues too - in terms of singleton destruction order - but sticking them on the heap doesn't usually solve anything.
Upvotes: 2
Reputation: 21601
Looking at the question from a different angle...
In C++ you can reference objects using pointers (Foo *
) and references (Foo &
). Wherever possible, I use a reference instead of a pointer. For instance, when passing by reference to a function/method, using references allows the code to (hopefully) make the following assumptions:
delete
the object. It's like saying, "Here, use this data but give it back when you're done".Upvotes: 1
Reputation: 3460
Yes, at first that makes sense, coming from a Java or C# background. It doesn't seem like a big deal to have to remember to free the memory you allocated. But then when you get your first memory leak, you'll be scratching your head, because you SWORE you freed everything. Then the second time it happens and the third you'll get even more frustrated. Finally after six months of headaches due to memory issues you'll start to get tired of it and that stack-allocated memory will start to look more and more attractive. How nice and clean -- just put it on the stack and forget about it. Pretty soon you'll be using the stack any time you can get away with it.
But -- there's no substitute for that experience. My advice? Try it your way, for now. You'll see.
Upvotes: 11
Reputation: 133138
I'd say it's a lot about a matter of taste. If you create an interface allowing methods to take pointers instead of references, you are allowing the caller to pass in nil. Since you allow the user to pass in nil, the user will pass in nil.
Since you have to ask yourself "What happens if this parameter is nil?", you have to code more defensively, taking care of null checks all the time. This speaks for using references.
However, sometimes you really want to be able to pass in nil and then references are out of the question :) Pointers give you greater flexibility and allow you to be more lazy, which is really good. Never allocate until know you have to allocate!
Upvotes: 4
Reputation: 3208
The first case is not always stack allocated. If it's part of an object, it'll be allocated wherever the object is. For example:
class Rectangle {
Pixel top_left;
Pixel bottom_right;
}
Rectangle r1; // Pixel is allocated on the stack
Rectangle *r2 = new Rectangle(); // Pixel is allocated on the heap
The main advantages of stack variables are:
Once the object's been created, there's no performance difference between an object allocated on the heap, and one allocated on the stack (or wherever).
However, you can't use any kind of polymorphism unless you're using a pointer - the object has a completely static type, which is determined at compile time.
Upvotes: 6
Reputation: 12024
A good general rule of thumb is to NEVER use new unless you absolutely have to. Your programs will be easier to maintain and less error prone if you don't use new as you don't have to worry about where to clean it up.
Upvotes: 11
Reputation: 10399
Object lifetime. When you want the lifetime of your object to exceed the lifetime of the current scope, you must use the heap.
If on the other hand, you don't need the variable beyond the current scope, declare it on the stack. It will automatically be destroyed when it goes out of scope. Just be careful passing its address around.
Upvotes: 4
Reputation: 20360
"Why not use pointers for everything in C++"
One simple answer - because it becomes a huge problem managing the memory - allocating and deleting/freeing.
Automatic/stack objects remove some of the busy work of that.
that is just the first thing that I would say about the question.
Upvotes: 14
Reputation: 65629
The best reason not to new everything is that you can very deterministic cleanup when things are on the stack. In the case of Pixel's this is not so obvious, but in the case of say a file, this becomes advantageous:
{ // block of code that uses file
File aFile("file.txt");
...
} // File destructor fires when file goes out of scope, closing the file
aFile // can't access outside of scope (compiler error)
In the case of newing a file, you would have to remember to delete it to get the same behavior. Seems like a simple issue in the above case. Consider more complex code, however, such as storing the pointers into a data structure. What if you pass that data structure to another piece of code? Who is responsible for the cleanup. Who would close all your files?
When you don't new everything, the resources are just cleaned up by the destructor when the variable goes out of scope. So you can have greater confidence that resources are successfully cleaned up.
This concept is known as RAII -- Resource Allocation Is Initialization and it can drastically improve your ability to deal with resource acquisition and disposal.
Upvotes: 6
Reputation: 7787
I prefer to use the first method whenever I get the chance because:
Upvotes: 24
Reputation: 268
My gut reaction is just to tell you that this could lead to serious memory leaks. Some situations in which you might be using pointers could lead to confusion about who should be responsible for deleting them. In simple cases such as your example, it's easy enough to see when and where you should call delete, but when you start passing pointers between classes, things can get a little more difficult.
I'd recommend looking into the boost smart pointers library for your pointers.
Upvotes: 6