This blog has discussed critical c++ concepts related to dangling pointers, bad pointers, memory leak, static memory, dynamic memory, reference variable, const and volatile keywords, template, etc.
A pointer is a special kind of variable designed to store the memory address of another variable. Declaring a pointer is as simple as declaring any other variable, but it is tricky to handle. The dangling pointer is a similar tricky situation!
A pointer pointing to a memory location that has been deleted/de-allocated or falls out of scope is called Dangling Pointer. Here are some questions to ponder upon!
Here are three scenarios when dangling pointers get created during coding:
A pointer to the memory that you have deleted
int main()
{
int num = 47;
int *ptr = #
free(num);
//ptr is pointing to a de-allocated memory
//dangling pointer
cout<< ptr << endl;
}
Returning local variable in a function call
int *fun()
{
int num = 47;
return #
}
int main()
{
int *ptr = fun();
//ptr falls out of scope
//dangling pointer
cout<< ptr << endl;
}
Pointing to a variable that is out of scope
int main()
{
int *ptr;
{
int num = 47;
ptr = #
}
// ptr goes out of scope
// dangling pointer
cout<< ptr << endl;
}
A memory leak occurs when memory resources are allocated and not properly released once no longer required, often introduced through bad coding practices. If a program has memory leaks, its memory usage increases, and since all systems have limited memory, it can create problems. Here are some questions for you to ponder upon!
Memory leak scenario 1
void function()
{
// memory allocated
int *ptr = new int [47];
// returning without de-allocating memory
return;
}
int main()
{
function();
return 0;
}
Memory leak scenario 2
void main()
{
// memory allocated
int *ptr = new int [47];
//reference to the memory removed
// without deallocating the memory
ptr = NULL;
free(ptr);
}
When a pointer is first allocated, it does not have a pointee i.e. pointer is "uninitialized" or "bad". A dereference operation on a bad pointer is a serious runtime error. The code will compile fine, but at run-time, each dereferences with a bad pointer will corrupt memory somehow. As a result, the program will crash sooner or later. The programmer's responsibility is to ensure that each pointer is assigned a pointee before it is used.
ย Suppose we allocate a pointer and free the associated memory after using it. If we try to use the pointer again, it'll end in undefined behavior: maybe a crash will occur that depends on the system/platform's state. So, the idea would be never to use a pointer after it has been freed. Even a good practice is to set the pointer to ๐ก๐จ๐๐ after it has been freed such that an access violation catches any attempt to use it again.
So, here are some critical questions to explore:
ย A stack is an area in a computer's memory that is responsible for storing ๐๐ฒ๐บ๐ฝ๐ผ๐ฟ๐ฎ๐ฟ๐ ๐๐ฎ๐ฟ๐ถ๐ฎ๐ฏ๐น๐ฒ๐. During runtime, variables are declared, stored, and initialized in the stack. Since the stack is temporary memory storage, the variables' memory gets automatically erased once the computational task is complete.
An attempt to free memory on the stack using the ๐ณ๐ฟ๐ฒ๐ฒ() function will throw an ๐ฎ๐ฐ๐ฐ๐ฒ๐๐ ๐๐ถ๐ผ๐น๐ฎ๐๐ถ๐ผ๐ป. Memory management on the stack(non-pointer variables) is carried out by the system implicitly.
Here are some critical questions to explore:
ย ๐๐ฒ๐ฎ๐ฝ memory, also known as ๐ฑ๐๐ป๐ฎ๐บ๐ถ๐ฐ memory, is an alternative to local stack memory. Local memory is quite automatic: it is allocated automatically on function calls and deallocated automatically when a function exits.
Heap memory is different in every way. The programmer has to explicitly request the allocation of a memory ๐ฏ๐น๐ผ๐ฐ๐ธ of a particular size, and the block continues to be allocated until the programmer explicitly requests that it be deallocated. ๐๐ฒ๐ฟ๐ฒ ๐ฎ๐ฟ๐ฒ ๐๐ผ๐บ๐ฒ ๐ฐ๐ฟ๐ถ๐๐ถ๐ฐ๐ฎ๐น ๐พ๐๐ฒ๐๐๐ถ๐ผ๐ป๐ ๐๐ผ ๐ฒ๐ ๐ฝ๐น๐ผ๐ฟ๐ฒ:
We can initialize a string in C++ in different ways, like a character array or character pointer. Each one of them has its pros and cons.
Here are some critical questions to explore:
A reference variable is an alias, that is, another name for an already existing variable/memory instance. Once a reference is initialized with a variable, either the variable name or the reference name may refer to the variable. The reference variable, once defined to refer to a variable, cannot be changed to point to other variables.
When passing by reference, the caller does not always need to use the "&" operator to compute a new pointer to the value of interest. Sometimes the caller already has a pointer to the value of interest, so no new pointer computation is required. The pointer to the value of interest can be passed through unchanged.
ย In C++, const is used to make some values constant throughout the program, or in other words, variables declared with the const keyword become constants and cannot be altered by the program.
Pointers can be declared using the const keyword too. When we use const with pointers, we can do it in two ways, either we can apply const to what the pointer is pointing to, or we can make the pointer itself a constant.
ย In the C/C++ programming language, a variable or object declared with the volatile keyword usually has special properties related to optimization on objects that can change in ways that the compiler cannot determine.
The optimizations are performed by caching variables in registers. The volatile keyword is designed to prevent the compiler from applying any optimizations on the code that assume values of variables cannot change "on their own."
ย The volatile keyword is intended to be used in combination with variables that are accessed and modified in different threads. Basically, without volatile, either writing multithreaded programs becomes difficult, or the compiler wastes vast optimization opportunities.
Templates allow us to write generic programs in C++. In simple terms, we can create a single function or a class to work with different data types using templates.
The idea of C++ templates is simple: we can make code dependent on parameters so that it can be used in different situations by instantiating the parameters as needed. In all programming languages, the most basic form of code that takes a parameter is a function.
Enjoy learning!