C++. Smart pointers. Automatic pointer. Class auto_ptr

Smart pointers. Automatic pointer. Class auto_ptr

It is recommended that you read the following topic before using this topic:


Contents


Search other resources:

1. The need to use smart pointers. Correctly creating and releasing a resource

In the C++ language, work with resources (files, memory) is performed based on the following statements. When memory is allocated for a resource, initialization occurs. That is, a pointer is created that points to the resource. When the program terminates, the resource must be freed. In the case of a file, that file must be closed. In the case of allocated memory, that memory must be freed.

However, a situation is possible when the process of program execution does not reach the moment of releasing the resource. This may be the case when an exception occurs while executing a program. In this case, the resource will remain unreleased. The following code demonstrates this situation for a file resource.

...

void main()
{
  // 1. Declare a pointer to a resource
  FILE* fp; // Pointer to resource

  // 2. Attempt to open a file
  if (!(fp = fopen("myFile.txt", "r")))
  {
    // if the file is not open then exit
    return;
  }

  // 3. If the file is open, then work with the file is performed
  // ...

  // An exception may occur here and the file will not be closed
  // !!!

  // 4. Closing a file if the program reaches this file
  fclose(fp);
}

In the above code in item 3, an exception may occur. As a result, the file will not be closed. And this is undesirable.

Solution. To solve this problem, you need to create a special class that will contain the following components:

  • the constructor in which the resource is initialized. In our case, a file is opened in the constructor;
  • the destructor in which the resource is freed. In our case, the file is closed.

After creating a class, you should create an object of this class, in which the resource (file) will be automatically created.

If an exception occurs in the program, the class object will be released, which will lead to the call of the destructor and, accordingly, the release of the resource.

In its most simplified form for a file resource, this special class has the form.

...

class InputFile
{
private:
  ifstream* p; // pointer to input stream
public:
  // The constructor in which the resource is created
  InputFile(const char* filename)
  {
    // Resource initialization
    p = new ifstream(filename);
    if (!(*p))
    {
      return;
    }
  }

  // Destructor
  ~InputFile()
  {
    p->close();
  }

  // Other elements of the class
  // ...
};

You can create your own classes following the example above.

Similar cases can also occur for memory operations when it is allocated and freed. The C++ language has a special class auto_ptr (automatic pointer), which ensures correct operation with any pointers pointing to an allocated memory fragment.

 

2. Class auto_ptr. Automatic pointer

The auto_ptr class is designed to work with objects that need to allocate and deallocate memory using the new operator. The class is placed in the std namespace.

When working with a pointer of type auto_ptr, you can work with a normal pointer pointing to a dynamic object created by the new operator. When the program terminates, the memory allocated for the dynamic object will be freed in the destructor of the auto_ptr class.

The class declaration is as follows

class std::auto_ptr<T>;

here T is the type of the object that the pointer points to.

The creation of an object of the auto_ptr class can be done in one of two ways

auto_ptr<T> p;
auto_ptr<T> p(pT);

here

  • p – an instance of the auto_ptr type;
  • T – is the type pointed to by instance p;
  • pT is a pointer pointing to the type T. This pointer contains the value of the memory address allocated by the new operator.

The auto_ptr class contains two functions:

T* get() const;
T* release();

where T – the type of the object that the auto_ptr pointer points to.

Method get() returns a pointer to an object of type T. The release() method returns a pointer to an object of type T, but takes ownership of the object from the auto_ptr pointer.

 

3. An example demonstrating the use of the auto_ptr pointer

The following is a demo application that uses an auto_ptr pointer. The program demonstrates the use of:

  • operator = when assigning pointers;
  • the get() method;
  • the release() method.

 

#include <iostream>
using namespace std;

void main()
{
  // The pointer of auto_ptr type
  // 1. Declaring a pointer p1 that points to the number 10
  auto_ptr<int> p1(new int(10));
  cout << "*p1 = " << *p1 << endl; // *p1 = 10

  // 2. Declaring the p2 pointer, which is currently nullptr
  auto_ptr<int> p2;

  // 3. Assignment of pointers.
  // On assignment, the memory allocated for p1 is freed 
  // and for p2 is allocated, or in other words: 
  // the resource is freed and the resource is allocated
  p2 = p1; // after that p1=nullptr, the value goes to p2

  cout << "*p2 = " << *p2 << endl; // *p2 = 10
  // cout << *p1 << endl; // error because memory for p1 has already been freed

  // 4. Method get() - return a regular pointer without passing ownership
  int* pI1;
  pI1 = p2.get();
  cout << "*pI1 = " << *pI1 << endl; // 10
  cout << "*p2 = " << *p2 << endl; // 10, the p2 pointer also points to 10

  // 5. The release() method is to get a pointer with transfer of ownership
  int* pI2;
  pI2 = p2.release(); // pI2=>10, p2=>nullptr
  cout << "*pI2 = " << *pI2 << endl; // 10

  // Checking the value p2
  if (p2.get() == nullptr)
    cout << "p2==nullptr" << endl; // +
  else
    cout << "p2!=nullptr" << endl;
}

Program result

*p1 = 10
*p2 = 10
*pI1 = 10
*p2 = 10
*pI2 = 10
p2==nullptr

 


Related topics