The difference is precisely whether to use the object as a value or as a reference. This is important because it determines where object data will be allocated.
The second way usually puts in the stack. Although I could put in the heap also if the object is being allocated in a type that is in the heap (if the declaration is placed directly on a container).
The shape with the operator new
will allocate memory in the heap and store the object there (the new
is the allocator, the MinhaClasse()
is the initializer). The value used for this variable will be a pointer (indirect), therefore it is considered a value by reference. This pointer which is the value to be used in this data is usually placed in the stack - example case - but can also be placed as a member of another object in the heap. Note that the pointer and the contents of the object are in the heap does not mean that they are together, on the contrary. They are independent things that have a relationship because a reference to another.
C++ lets the consumer decide where they want to allocate. This is different from Java for example, where all objects are allocated in heap through pointers - except the primitive types, as pointed out in the question. The philosophy of C++ is not to facilitate the use but to facilitate the best use of computational resources. The consumer has more information than is best at the time.
Life time usually determines more how allocation is done. Even if you have a relatively large object to be allocated and the programmer knows that he will only live within that scope or he understands well and the scope and he can be easily determined, that there is no risk of recursive calls or other functions allocating other large objects, it is possible to allocate in the stack no pointer. It is not common practice, it is difficult to do right and only compensates in cases of extreme optimization.
It is possible to create pointers to the stack also, without the use of the new
. This is also unusual. It is more common to use a reference for this, which is a pointer below the scenes, but you don’t need to know this and the control is better, although it can give some problems in the current version of C++ if the life time is shorter than expected (There is forecast for future releases not to let this happen in the same line as Rust does and does not let use wrong lifespan).
Object size
In cases where the object is large the copy will cost expensive, so it is better to store in a location that the life time can be indeterminate and access this information through an indirect (a pointer). This is usually less efficient, so the use of reference is more adopted.
In general when the object has a certain size and is small, it does not make sense to use the direct pointer (reference yes). Even if the die has a lifetime beyond the function where it is being used (see how the stack) or needs to be used outside an object where it is declared, the copy of the data that may be required in these cases can cost very cheap.
Of course some objects can be large, then usually consider the worst case. There is a situation where the consumer has more information. A type may have been created considering that the object may be large but in a specific use case it has a certain size and is small. In Java this would not be considered. In C++ a good programmer chooses to use the allocation inline, possibly in stack.
But small objects can be used by reference when it is known that they have a certain lifespan yet not so obvious.
Indeterminating the size of the object may be another good reason to prefer the use of pointer. Even if you know that the object will be small but cannot determine its exact size, how do you linearize it within another object? Creating a pointer that has fixed size referencing the actual object that has variable size.
Exchange is not so free
There are cases where the type was created thinking of a form of allocation and use otherwise will probably bring problems.
It is common to use some standard other than documentation to inform which is the preferred form of allocation. You can use struct
for cases where you should allocate the direct value and class
when the preference is to use an indirect. Some languages such as C# and D, and in a certain way Java, if you consider that primitive types act as structures (and that future Java will probably have the programmer create his own), determine the form of allocation depending on how the type was declared. To C++ struct
and class
are almost synonymous (the only difference is the visibility default of its members) and does not determine the allocation. At most developers are recommended to adopt this convention.
In general changeable types are better when allocated through pointers or references, otherwise a phenomenon called slicing.
A pointer is an indirect, which gives some flexibility.
Pointer management
Remembering that in most cases, in C++, one should use the smart pointers and not raw pointers. Thus you gain automatic memory management. If there is no internal mechanism in the class itself or the allocation system (new
can be overloaded and can even allocate on a Garbage Collector, although unusual and impractical today in C++) the programmer has to ensure that the delete
correspondent be executed.
Some cases the type indicates a semantics and controls the use of pointers on its own. String
is an example of a class that internalizes the pointer. It is a case that in general has no reason to allocate a pointer because the data that the program has direct access is small, the large and variable part of the text will be better allocated by the class, possibly using a pointer (it can optimize small cases and not do this, depends on implementation).
Completion
The choice should always be to allocate in stack - which is relatively small and basically fixed - until there is a reason to choose the heap, and the main reason is that the data must survive at the end of a function and be potentially too large to be copied. A secondary reason is potentially too big to fit in stack or make an object of indeterminate size or too large.
I think for large objects that will be passed to other objects is used with pointer. Already the creation
MinhaClasse mc2;
requires the passage by copy.– Rafael Bluhm