-1

Probably this question was already asked but I couldn't find it. Please redirect me if you you saw something. Question : what is the benefit of using :

myClass* pointer;

over

myClass* pointer = new(myClass);

From reading on other topics, I understand that the first option allocates a space on the stack and makes the pointer point to it while the second allocates a space on the heap and make a pointer point to it. But I read also that the second option is tedious because you have to deallocate the space with delete. So why would one ever use the second option. I am kind of a noob so please explain in details.

edit

#include <iostream>

using namespace std;

class Dog
{
        public:
                void bark()
                {
                        cout << "wouf!!!" << endl;
                }

};


int main()
{

        Dog* myDog = new(Dog);
        myDog->bark();
        delete myDog;
        return 0;

}

and

#include <iostream>

using namespace std;

class Dog
{
        public:
                void bark()
                {
                        cout << "wouf!!!" << endl;
                }

};


int main()
{

        Dog* myDog;
        myDog->bark();
        return 0;

}

both compile and give me "wouf!!!". So why should I use the "new" keyword?

roi_saumon
  • 489
  • 4
  • 13
  • The first option doesn't allocate anything except for the pointer itself. Where that storage is located depends on usage. I think you may have an extra `*` in your first example. – François Andrieux Feb 07 '18 at 20:52
  • Stack and Heap are implementation details that the language doesn't care about. What you're asking about is automatic vs dynamic storage duration. – lcs Feb 07 '18 at 20:54
  • 2
    Can i point you at the book list: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Richard Critten Feb 07 '18 at 20:54
  • The stack is limited, sometimes a few kB, sometimes 2-8MB, so if you have large images, or dynamically growing lists, you may need to use the heap. The stack also disappears when you return from a function, which is a problem for things you want to keep. – Mark Setchell Feb 07 '18 at 21:08
  • Also [possible duplicate](https://stackoverflow.com/questions/32514923/why-did-heap-memory-come-into-existence). – n. m. could be an AI Feb 07 '18 at 21:30
  • The first option you listed is incorrect. The second option violates current design principles. This question would have made sense several years ago, if you had gotten it right. The answer depends on scope and ownership, but you didn't give enough info on either. – Kenny Ostrom Feb 07 '18 at 21:52

1 Answers1

6

I understand that the first option allocates a space on the stack and makes the pointer point to it while the second allocates a space on the heap and make a pointer point to it.

The above is incorrect -- the first option allocates space for the pointer itself on the stack, but doesn't allocate space for any object for the pointer to point to. That is, the pointer isn't pointing to anything in particular, and thus isn't useful to use (unless/until you set the pointer to point to something)

In particular, it's only pure blind luck that this code appears to "work" at all:

Dog* myDog;
myDog->bark();   // ERROR, calls a method on an invalid pointer!

... the above code is invoking undefined behavior, and in an ideal world it would simply crash, since you are calling a method on an invalid pointer. But C++ compilers typically prefer maximizing efficiency over handling programmer errors gracefully, so they typically don't put in a check for invalid-pointers, and since your bark() method doesn't actually use any data from the Dog object, it is able to execute without any obvious crashing. Try making your bark() method virtual, OTOH, and you will probably see a crash from the above code.

the second allocates a space on the heap and make a pointer point to it.

That is correct.

But I read also that the second option is tedious because you have to deallocate the space with delete.

Not only tedious, but error-prone -- it's very easy (in a non-trivial program) to end up with a code path where you forgot to call delete, and then you have a memory leak. Or, alternatively, you could end up calling delete twice on the same pointer, and then you have undefined behavior and likely crashing or data corruption. Neither mistake is much fun to debug.

So why would one ever use the second option.

Traditionally you'd use dynamic allocation when you need the object to remain valid for longer than the scope of the calling code -- for example, if you needed the object to stick around even after the function you created the object in has returned. Contrast that with a stack allocation:

myClass someStackObject;

... in which someStackObject is guaranteed to be destroyed when the calling function returns, which is usually a good thing -- but not if you need someStackObject to remain in existence even after your function has returned.

These days, most people would avoid using raw/C-style pointers entirely, since they are so dangerously error-prone. The modern C++ way to allocate an object on the heap would look like this:

std::shared_ptr<myClass> pointer = std::make_shared<myClass>();

... and this is preferred because it gives you a heap-allocated myClass object whose pointed-to-object will continue to live for as long as there is at least one std::shared_ptr pointing to it (good), but also will automagically be deleted the moment there are no std::shared_ptr's pointing to it (even better, since that means no memory leak and no need to explicitly call delete, which means no potential double-deletes)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Hi, thanks for the nice answer. "but doesn't allocate space for any object for the pointer to point to" Oh, I see, I was probably confused : Does `int* ptr;` also just alocate space for the pointer itself or also for the int it is going to point to? (Maybe for this I got confused). "Traditionally you'd use the second object when you need the object to remain valid for longer than the scope of the calling code" I just tried to do this : `void foo() { Dog* myDog = new(Dog); } int main() { foo(); myDog.bark(); return 0; }` – roi_saumon Feb 07 '18 at 23:22
  • Oh, I just notice there is no newline. I'm not sure this is the right way to answer an answer... – roi_saumon Feb 07 '18 at 23:26
  • For any type, any time you just declare a pointer (e.g. X* x;) you are only allocating space for the pointer itself. Allocating space for an actual object of type X must be done separately (e.g. X* x = new X(); ... or equivalent, X * x; x = new X();) – Jeremy Friesner Feb 08 '18 at 00:06
  • 1
    In your longer-scope example in your comment, you might do it more like this: `Dog * foo() { Dog* myDog = new Dog; return myDog; } int main() { Dog * d = foo(); d->bark(); delete d; } – Jeremy Friesner Feb 08 '18 at 00:08
  • Okay, makes sense – roi_saumon Feb 08 '18 at 11:11
  • So when you return the pointer, you can still point to the object it points to because this one exists on the heap, whereas for the code bellow : `Dog* foo() {Dog myDog(3); Dog* ptr = &myDog; return ptr;} int main() { Dog* d = foo(); d->bark(); cout << d->age << endl; return 0;} ` (I just added a attribute for the age) the pointer is return but dereferencing it gives undefined behaviour since the object it points was destroyed because was on the stack. Is this it? I am now going to inform myself about unique_ptr and shared_ptr :) – roi_saumon Feb 08 '18 at 11:17
  • Yes, that's correct. Returning a pointer to a stack object is always a mistake, for that reason :) – Jeremy Friesner Feb 08 '18 at 16:54