2020 Full-time Interview CCJ’s Preparation (3): C++ 11 New Features

see: 2020 Full-time Interview CCJ’s Preparation (1): Commonly Asked C++ Interview Questions, at this link.

see: 2020 Full-time Interview CCJ’s Preparation (2): Commonly Asked C++ Interview Questions in a Table, at this link.

1. Uses for smart pointers (Modern C++)

see: https://docs.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp?view=msvc-160

1) Uses for smart pointers

Smart pointers are defined in the std namespace in the <memory> header file. They are crucial to the RAII or Resource Acquisition Is Initialization programming idiom. The main goal of this idiom is to ensure that resource acquisition occurs at the same time that the object is initialized, so that all resources for the object are created and made ready in one line of code. In practical terms, the main principle of RAII is to give ownership of any heap-allocated resource—for example, dynamically-allocated memory or system object handles — to a stack-allocated object whose destructor contains the code to delete or free the resource and also any associated cleanup code.

In most cases, when you initialize a raw pointer or resource handle to point to an actual resource, pass the pointer to a smart pointer immediately. In modern C++, raw pointers are only used in small code blocks of limited scope, loops, or helper functions where performance is critical and there is no chance of confusion about ownership.

The following example compares a raw pointer declaration to a smart pointer declaration.

void UseRawPointer()
{
// Using a raw pointer -- not recommended.
Song* pSong = new Song(L"Nothing on You", L"Bruno Mars");
// Use pSong...
// Don't forget to delete!
delete pSong;
}
void UseSmartPointer()
{
// Declare a smart pointer on stack and pass it the raw pointer.
unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));
// Use song2...
wstring s = song2->duration_;
//...
} // song2 is deleted automatically here.

As shown in the example, a smart pointer is a class template that you declare on the stack, and initialize by using a raw pointer that points to a heap-allocated object. After the smart pointer is initialized, it owns the raw pointer. This means that the smart pointer is responsible for deleting the memory that the raw pointer specifies. The smart pointer destructor contains the call to delete, and because the smart pointer is declared on the stack, its destructor is invoked when the smart pointer goes out of scope, even if an exception is thrown somewhere further up the stack.

Access the encapsulated pointer by using the familiar pointer operators, -> and *, which the smart pointer class overloads to return the encapsulated raw pointer.

The C++ smart pointer idiom resembles object creation in languages such as C#: you create the object and then let the system take care of deleting it at the correct time.

Alt text

The following example shows how a unique_ptr smart pointer type from the C++ Standard Library could be used to encapsulate a pointer to a large object.

class LargeObject
{
public:
void DoSomething(){}
};
void ProcessLargeObject(const LargeObject& lo){}
void SmartPointerDemo()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Pass a reference to a method.
ProcessLargeObject(*pLarge);
} //pLarge is deleted automatically when function block goes out of scope.

Smart pointers are designed to be as efficient as possible both in terms of memory and performance. For example, the only data member in unique_ptr is the encapsulated pointer. This means that unique_ptr is exactly the same size as that pointer, either four bytes or eight bytes. Accessing the encapsulated pointer by using the smart pointer overloaded * and -> operators is not significantly slower than accessing the raw pointers directly.

Smart pointers have their own member functions, which are accessed by using "dot" notation. For example, some C++ Standard Library smart pointers have a reset member function that releases ownership of the pointer. This is useful when you want to free the memory owned by the smart pointer before the smart pointer goes out of scope, as shown in the following example.

void SmartPointerDemo2()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Free the memory before we exit function block.
pLarge.reset();
// Do some other work...
}

Smart pointers usually provide a way to access their raw pointer directly. C++ Standard Library smart pointers have a get member function for this purpose, and CComPtr has a public p class member. By providing direct access to the underlying pointer, you can use the smart pointer to manage memory in your own code and still pass the raw pointer to code that does not support smart pointers.

void SmartPointerDemo4()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Pass raw pointer to a legacy API
LegacyLargeObjectFunction(pLarge.get());
}

2) Kinds of smart pointers in C++ Standard Library smart pointers

Use these smart pointers as a first choice for encapsulating pointers to plain old C++ objects (POCO).

unique_ptr:

shared_ptr:

weak_ptr:

2. Smart pointer in C++ and It’s Types

see: https://www.geeksforgeeks.org/smart-pointers-cpp/

Things to learn in this article:

1) Importance of pointer in C/C++:

Pointers are used for accessing the resources which are external to the program like heap memory. So for accessing the heap memory if anything is created inside heap memory Pointers are used.

2) Problem with normal pointer:

Let’s understand what’s the main problem with the normal pointer by taking a small C++ program using this illustration.

#include <iostream>
using namespace std;
class Rectangle {
private:
int length;
int breadth;
};
void fun()
{
// By taking a pointer p and
// dynamically creating object
// of class rectangle
Rectangle* p = new Rectangle();
}
int main()
{
// Infinite Loop
while (1) {
fun();
}
}

So what happens is it’ll have a pointer ‘p’ and this will be pointing to an object of type rectangle which will have length and breadth. Once the function ends this ‘p’ is deleted because p is a local variable to the function which will end but a new rectangle that is allocated inside heap that will not be deallocated. And it will return it will come back as its infinite loop again it will call, so again new p is created then again a new object is created for rectangle same length and breadth. So then what about the previous object, it’ll not be deleted, again extra new object, it’ll also not deleted. So every time it will create an object but not it’s deleting so this is causing leakage of memory from the heap memory. Like for memory for length and breadth is unused though it’s allocated but not in use. So slowly the entire heap memory may become unused because it’s infinite. So at one stage because of a lack of heap memory, the program will crash. So at the last of the fun() we should use ‘delete p’ if we do not mention this, this will cause a very severe problem. So because of the laziness or carelessness of the programmer this type of problem may arise. So to help the programmer C++ 11 takes responsibility and introduces smart pointers.

3) Introduction of Smart Pointers

The problem with heap memory is that when you don’t need it you must deallocate itself. So mostly the programmers are too lazy in writing the code for deallocation of objects and that causes severe problem like memory leak which will cause the program to crash. So the languages like Java, C#, .Net Framework they provide a garbage collection mechanism to deallocate the object which is not in use.

So in C++ 11, it introduces smart pointers that automatically manage memory and they will deallocate the object when they are not in use when the pointer is going out of scope automatically it’ll deallocate the memory.

Consider the following simple C++ code with normal pointers.

brightness_4
MyClass* ptr = new MyClass();
ptr->doSomething();
// We must do delete(ptr) to avoid memory leak

Using Smart Pointers, we can make pointers to work in a way that we don’t need to explicitly call delete. A smart pointer is a wrapper class over a pointer with an operator like * and -> overloaded. The objects of smart pointer class look like a pointer but can do many things that a normal pointer can’t, like automatic destruction (yes, we don’t have to explicitly use delete), reference counting and more.

The idea is to take a class with a pointer, destructor and overloaded operators like * and ->. Since the destructor is automatically called when an object goes out of scope, the dynamically allocated memory would automatically be deleted (or reference count can be decremented). Consider the following simple smart ptr class.

#include <iostream>
using namespace std;
class SmartPtr {
int* ptr; // Actual pointer
public:
// Constructor: Refer https:// www.geeksforgeeks.org/g-fact-93/
// for use of explicit keyword
explicit SmartPtr(int* p = NULL) { ptr = p; }
// Destructor
~SmartPtr() { delete (ptr); }
// Overloading dereferencing operator
int& operator*() { return *ptr; }
};
int main()
{
SmartPtr ptr(new int());
*ptr = 20;
cout << *ptr;
// We don't need to call delete ptr: when the object
// ptr goes out of scope, the destructor for it is automatically
// called and destructor does delete ptr.
return 0;
}
20

Writing one smart pointer class that works for all types.

Yes, we can use templates to write a generic smart pointer class. Following C++ code demonstrates the same.

#include <iostream>
using namespace std;
// A generic smart pointer class
template <class T>
class SmartPtr {
T* ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T* p = NULL) { ptr = p; }
// Destructor
~SmartPtr() { delete (ptr); }
// Overloading dereferncing operator
T& operator*() { return *ptr; }
// Overloading arrow operator so that
// members of T can be accessed
// like a pointer (useful if T represents
// a class or struct or union type)
T* operator->() { return ptr; }
};
int main()
{
SmartPtr<int> ptr(new int());
*ptr = 20;
cout << *ptr;
return 0;
}
20

Note: Smart pointers are also useful in the management of resources, such as file handles or network sockets.

4) Types of Smart Pointer:

a) unique_ptr

If you are using a unique pointer then if one object is created and pointer P1 is pointing to this one them only one pointer can point this one at one time. So we can’t share with another pointer, but we can transfer the control to P2 by removing P1.

Alt text

#include <iostream>
using namespace std;
#include <memory>
class Rectangle {
int length;
int breadth;
public:
Rectangle(int l, int b)
{
length = l;
breadth = b;
}
int area()
{
return length * breadth;
}
};
int main()
{
unique_ptr<Rectangle> P1(new Rectangle(10, 5));
cout << P1->area() << endl; // This'll print 50
// unique_ptr<Rectangle> P2(P1);
unique_ptr<Rectangle> P2;
P2 = move(P1);
// This'll print 50
cout << P2->area() << endl;
// cout<<P1->area()<<endl;
return 0;
}
50
50

b) shared_ptr

If you are using shared_ptr then more than one pointer can point to this one object at a time and it’ll maintain a Reference Counter using use_count() method.

Alt text

#include <iostream>
using namespace std;
#include <memory>
class Rectangle {
int length;
int breadth;
public:
Rectangle(int l, int b)
{
length = l;
breadth = b;
}
int area()
{
return length * breadth;
}
};
int main()
{
shared_ptr<Rectangle> P1(new Rectangle(10, 5));
// This'll print 50
cout << P1->area() << endl;
shared_ptr<Rectangle> P2;
P2 = P1;
// This'll print 50
cout << P2->area() << endl;
// This'll now not give an error,
cout << P1->area() << endl;
// This'll also print 50 now
// This'll print 2 as Reference Counter is 2
cout << P1.use_count() << endl;
return 0;
}
50
50
50
2

c) weak_ptr

It’s much more similar to shared_ptr except it’ll not maintain a Reference Counter. In this case, a pointer will not have a strong hold on the object. The reason is if suppose pointers are holding the object and requesting for other objects then they may form a Deadlock.

Alt text

C++ libraries provide implementations of smart pointers in the form of auto_ptr, unique_ptr, shared_ptr and weak_ptr.


End of the file
Nov. 28, 2020, by CCJ at Secaucus, NJ, US.