c++classpointersdynamic-memory-allocationstatic-memory-allocation

What are the reasons to allocate a pointer on the heap?


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?


Solution

  • 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)