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.
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.
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
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;
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
}
};
This kind of behavior is used in the Strategy design pattern.
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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With