Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use 'new' when creating objects with associated pointers?

I am learning C++ by reading a textbook. The "objects and pointers" part says, that declaring a pointer to an object like this :

SomeClass *ptrMyClass;

does nothing by itself. Only after defining an instance of Class does it make sense, like this :

SomeClass *ptrMyClass;
ptrMyClass = new SomeClass;

Or by combining these together in :

SomeClass *ptrMyClass = new SomeClass;

My question is, why do we have to create an instance of SomeClass on the heap by using 'new' ? So far in the book, pointers always pointed to 'normal' variables ( like int, float... ) that weren't created by using 'new'. Thank you.

like image 704
James C Avatar asked Feb 06 '14 23:02

James C


5 Answers

There are two main ways of instantiating objects in C++: stack and heap (or free store). For example:

void func()
{
    // On the stack:
    Widget blah;

    // On the heap:
    Widget * foo = new Widget;
    delete foo;
}

The advantage of stack objects/variables is that they tend to be a little a faster to allocate/access, and they are slightly easier to work with. However, the stack is a limited size, and the data is usually limited to local scope (with the exception of global variables, which are usually inadvisable). That is, the blah object in the example above will be automatically destroyed as soon as func() ends. There's nothing you can do about that. Any pointers to stack objects/variables therefore become invalid (aka 'dangling') when the original item goes out of scope.

The heap is (typically) much bigger, so it can cope with a lot more data than the stack. It tends to be slightly slower, but it has the advantage of letting you reallocate things at run-time. By contrast, stack objects/variables (and especially arrays) are fixed at compile-time.

Additionally, after an object has been allocated on the heap, you can leave it there for as long as you need it, maintaining valid pointers to it. In the past, you would have to call delete eventually to avoid a memory leak. In modern C++, smart pointers are encouraged instead (e.g. std::shared_ptr).

As an additional note, it gets slightly more complex when declaring members of a class. If the object is instantiated on the stack, then any of its direct members (i.e. members by composition) will be on the stack too. If the object is instantiated on the heap, then all of its members will be on the heap.

like image 137
Peter Bloomfield Avatar answered Oct 25 '22 01:10

Peter Bloomfield


My question is, why do we have to create an instance of SomeClass on the heap by using 'new' ?

You don't. You can dynamically create an object with new. Alternatively you can get a pointer to an existing object

SomeClass* ptrMyClass1;     // An uninitialized pointer.

                            // If an automatic object its value is indeterminate and
                            // You have not defined what it points at. It should not
                            // be used (until you explicitly set it to something).

                            // If a static object then it is initialized to NULL
                            // i.e. Global (or other static storage duration object).

SomeClass* ptrMyClass2 = new SomeClass; // A pointer to a dynamically 
                                        // allocated object.

SomeClass  objMyClass3;                 // A normal object
SomeClass* ptrMyClass4 = &objMyClass3;  // A pointer to a normal object
like image 42
Martin York Avatar answered Oct 25 '22 00:10

Martin York


Why create an instance of a class in the heap

There is a case when you have to do this kind of stuff.

When you're using an abstract class with no concrete methods, and classes that inherit from that abstract class (in Java or PHP world we would talk about inheritance from an interface):

class IMyAbstractClass
{
public:
    virtual int myFunction(void) = 0;
};

class MyInheritedClass : public IMyAbstractClass
{
public:
    int myFunction(void)
    {
        // doSomething
        return 0;
    }
};

If you need to refer to instances of inherited classes, by the abstract class they inherit from, then the syntax is:

IMyAbstractClass * myInstance;
myInstance = new MyInheritedClass;

So what does it allow you to do?

After having declared your object this way, you can pass it to another object's constructor as being an instance of IMyAbstractClass:

AnotherClass anotherObject(myInstance);

This constructor being coded like that:

class AnotherClass
{
public:
    AnotherClass(IMyAbstractClass * instance)
    {
        // doSomething
    }
};

Real life example anywhere?

This kind of behavior is used in the Strategy design pattern.

like image 43
Jivan Avatar answered Oct 25 '22 00:10

Jivan


why do we have to create an instance of SomeClass on the heap by using 'new' ?

You don't have to. You can also reference an instance created on the stack:

SomeClass some;
SomeClass* ptrMyClass(&some);
like image 34
justin Avatar answered Oct 25 '22 00:10

justin


Modern theorists dislike to use term "heap" in relation to dynamic allocation of objects. It's not clear how this term is coined but it conflicts with the name of so-called heap-like structures (a set with particular properties, a pile). C++ standard doesn't use such term.

The main difference between static, automatic and dynamic allocation is self-explnatory if such terms are used. Statically allocated objects have predetermined identity, even if in given context. They are named, their count and size fully defined at compile time.

Automatically created objects are result of a entry to a function or code block. Their names are known as local variables. Within particular block they have identity predefined by program, but every recursive or parallel call to fuction would create another copy automatically. They are destroyed at exit.

Dynamically allocated objects can be created as many times as programmer desires and decision whether to create one or not and how many can be made during execution, no new stack frame is required. Those objects can't be named, but can be referenced and some relation between locations of objects or subobjects can be deduced by pointer arithmetics. One could say that dynamic allocation can create a pile of objects, hence a result of any pointer arithmetic operations applied to objects which are not subobjects of same object is undefined.

In C++ the only way to create array of size unknown to programmer is dynamic allocation. C99 had portable analig of 'alloca' function, known as Variable Length Array, which allocates such array within stack frame. Some popular C++ compilers support VLA as an extension, to dismay of code checkers and confusion of beginners.

like image 41
Swift - Friday Pie Avatar answered Oct 25 '22 01:10

Swift - Friday Pie