C++ Core Concepts & Memory Handling Interview Questions (original) (raw)

C++ is a mid-level language combining high-level abstractions (classes, inheritance, templates) with low-level memory control (pointers, dynamic allocation). Core concepts include variables, functions, references, operators, and object-oriented features like encapsulation and polymorphism. Memory handling covers stack vs heap allocation, pointers, dynamic memory (new/delete), deep vs shallow copies, and smart pointers.

1. How do you free memory allocated with new?

Use delete for single values, and delete[] for arrays:

C++ `

#include using namespace std;

int main() {

int* p = new int;
delete p;

int* arr = new int[10];
delete[] arr;

return 0;

}

`

2. What is the difference between new and malloc()?

Following are the major difference between new and malloc()

new malloc()
An operator which performs an operation A function that returns and accepts values
Calls the constructors Cannot call a constructor
Returns the exact data type Returns void*

3. What happens if we change pointer ?

If you pass a pointer by value but forget to use dereferencing, changes won’t reflect.

**Code:

C++ `

#include using namespace std;

void wrongUpdate(int *p) { int x = 100; p = &x; // Changing the pointer locally, not the original address }

int main() { int a = 10; int *ptr = &a; wrongUpdate(ptr); cout << "Value: " << *ptr << endl; // Will still print 10 return 0; }

`

4. How internally delete and delete[] works in cpp?

**delete and **delete[] deallocate memory obtained from new and new[].

The compiler typically keeps track of the number of elements internally (implementation-defined).

**Note: The actual destructor calls and memory release are handled automatically by the compiler/runtime; programmers should never explicitly invoke ptr->~T() before delete.

**Example of delete:

C++ `

ptr->~T(); // Call destructor operator delete(ptr); // Free memory

`

**Example of delete[]:

C++ `

for (int i = size - 1; i >= 0; --i) arr[i].~T(); // Call destructor on each operator delete; // Free memory

`

Note: If the object is a primitive type (int, char), destructors aren't needed.

5. How we can make custom delete?

You can overload operator delete or operator delete[] in your class:

C++ `

void operator delete(void* ptr) { std::cout << "Custom delete\n"; ::operator delete(ptr); }

`

6. What happens if you return a pointer to a local variable from a function?

The pointer becomes dangling because the variable’s lifetime ends when the function exits. Accessing it causes undefined behavior.

C++ `

int* foo() { int x = 10; return &x;
}

`

7. Demonstrate shallow vs deep copy in C++ with memory implications.

C++ `

#include using namespace std;

int main() {

// Shallow Copy
int *a = new int(10);
int *b = a;   // shallow copy: both point to same memory

*b = 20;      // changing b also changes a
cout << "Shallow Copy:" << endl;
cout << "a = " << *a << ", b = " << *b << endl;  // both 20

// Deep Copy 
int *x = new int(10);
int *y = new int(*x);  // deep copy: new memory with same value

*y = 30;      // changing y does not affect x
cout << "\nDeep Copy:" << endl;
cout << "x = " << *x << ", y = " << *y << endl;  // x=10, y=30

delete a; // free memory
// delete b;  // dangerous in shallow copy (same memory as a)
delete x;
delete y;

return 0;

}

`

Output

Shallow Copy: a = 20, b = 20

Deep Copy: x = 10, y = 30

8. Explain why delete cannot be used for arrays with demonstration?

**Example:

C++ `

#include using namespace std;

int main() { int* arr = new int[3]{1, 2, 3};

delete arr;       // Wrong: only first element destructor called
// delete[] arr;  // Correct: destructors for all elements

return 0;

}

`

9. Show why base class destructors should be virtual.?

**Example:

C++ `

#include using namespace std;

class Base { public: Base() { cout << "Base constructor\n"; } ~Base() { cout << "Base destructor\n"; } // Non-virtual };

class Derived : public Base { public: Derived() { cout << "Derived constructor\n"; } ~Derived() { cout << "Derived destructor\n"; } };

int main() { Base* obj = new Derived(); delete obj; // Derived destructor not called: memory leak return 0; }

`

Output

Base constructor Derived constructor Base destructor

10. How do auto and decltype improve type safety? Show with example.

**Example:

C++ `

#include #include using namespace std;

int main() { vector v = {1, 2, 3};

// auto deduces type
auto it = v.begin();  // deduced as vector<int>::iterator
cout << *it << endl;

// decltype deduces type of expression
decltype(v)::iterator it2 = v.end();
cout << *(--it2) << endl;

return 0;

}

`

12. Show how mutable allows changing internal state even in a const object?

**Example:

C++ `

#include using namespace std;

class Example { mutable int accessCount; // can be modified even in const object public: Example() : accessCount(0) {} void show() const { accessCount++; // allowed because 'accessCount' is mutable cout << "Access count = " << accessCount << endl; } };

int main() { const Example obj; // const object obj.show(); // modifies mutable member obj.show(); }

`

Output

Access count = 1 Access count = 2

Even though obj is const, the mutable member (accessCount) can still be changed.

13. How does pointer arithmetic lead to undefined behavior if misused?

**Example cases:

  1. Incrementing past the end of an array.
  2. Decrementing before the start of an array.
  3. Adding large offsets that go far beyond allocated memory.

**Code Example:

C++ `

#include using namespace std;

int main() { int arr[3] = {1, 2, 3}; int* ptr = arr;

cout << *(ptr + 2) << endl;   // valid, outputs 3
cout << *(ptr + 5) << endl;   // Undefined behavior

return 0;

}

`

14. Demonstrate difference in memory layout and access.

So the difference is in layout:

**Example:

C++ `

#include using namespace std;

int main() { int a = 1, b = 2, c = 3;

int* arrOfPtrs[3] = {&a, &b, &c};   // Array of pointers
int (*ptrToArr)[3] = new int[1][3]; // Pointer to array
(*ptrToArr)[0] = 10; (*ptrToArr)[1] = 20; (*ptrToArr)[2] = 30;

cout << *arrOfPtrs[1] << endl;       // Output: 2
cout << (*ptrToArr)[1] << endl;      // Output: 20

delete[] ptrToArr;

}

`