C++ Introductory Tutorial||C++ Dynamic Memory||C++ Namespace

C++ dynamic memory

C++ dynamic memory

Knowing how dynamic memory works in C++ is essential to being a good C++ programmer. Memory in a C++ program is divided into two parts:

  • Stack: All variables declared inside a function will occupy stack memory.
  • Heap: This is unused memory in the program, which can be used to dynamically allocate memory while the program is running.

In many cases, you cannot predict in advance how much memory is needed to store specific information in a defined variable, and the size of the required memory needs to be determined at runtime.

In C++, you can allocate memory on the heap at runtime for a variable of a given type using special operators, which return the address of the allocated space. This operator is  the new  operator.

If you don't need to dynamically allocate memory, you can use  the delete  operator to delete memory previously allocated by the new operator.

new and delete operators

The following is the general syntax for dynamically allocating memory for any data type using the new operator:

new data-type;

Here, data-type  can be any built-in data type including array, or any user-defined data type including class or structure. Let's first look at the built-in data types. For example, we can define a pointer to type double and then request memory, which is allocated at execution time.  We can do this using the new operator as follows  :

double* pvalue = NULL; // pointer initialized to null
pvalue = new double; // request memory for variable

If the free store is exhausted, memory allocation may not be successful. So it is recommended to check whether the new operator returns a NULL pointer and take the following appropriate action:

double* pvalue  = NULL;
if( !(pvalue  = new double ))
{
   cout << "Error: out of memory." <<endl;
   exit(1);

}

The malloc()  function has appeared in the C language, and it still exists in C++, but it is recommended not to use the malloc() function as much as possible. The main advantage of new over the malloc() function is that new doesn't just allocate memory, it also creates objects.

At any time, when you feel that a variable that has dynamically allocated memory is no longer needed, you can use the delete operator to release the memory it occupies, as follows:

delete pvalue; // release the memory pointed to by pvalue

The above concepts are used in the following example, demonstrating how to use the new and delete operators:

#include <iostream>
using namespace std;

int main ()
{
   double* pvalue  = NULL; // 初始化为 null 的指针
   pvalue  = new double;   // 为变量请求内存
 
   *pvalue = 29494.99;     // 在分配的地址存储值
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // 释放内存

   return 0;
}

When the above code is compiled and executed, it produces the following result:

Value of pvalue : 29495

Dynamic memory allocation for arrays

Suppose we want to allocate memory for a character array (a string of 20 characters), we can use the syntax in the above example to dynamically allocate memory for the array, as follows:

char* pvalue = NULL; // pointer initialized to null
pvalue = new char[20]; // request memory for variable

To delete the array we just created, the statement is as follows:

delete [] pvalue; // delete the array pointed to by pvalue

The following is the general syntax of the new operator, which can allocate memory for multidimensional arrays, as follows:

int ROW = 2;
int COL = 3;
double **pvalue  = new double* [ROW]; // 为行分配内存

// 为列分配内存
for(int i = 0; i < COL; i++) {
    pvalue[i] = new double[COL];
}

Free the multidimensional array memory:

for(int i = 0; i < COL; i++) {
    delete[] pvalue[i];
}
delete [] pvalue; 

Dynamic memory allocation of objects

Objects are no different than simple data types. For example, take a look at the following code, where we use an array of objects to clarify this concept:

#include <iostream>
using namespace std;

class Box
{
   public:
      Box() { 
         cout << "调用构造函数!" <<endl; 
      }
      ~Box() { 
         cout << "调用析构函数!" <<endl; 
      }
};

int main( )
{
   Box* myBoxArray = new Box[4];

   delete [] myBoxArray; // Delete array

   return 0;
}

If you want to allocate memory for an array of four Box objects, the constructor will be called 4 times, and similarly, when these objects are deleted, the destructor will be called the same number of times (4 times).

When the above code is compiled and executed, it produces the following result:

Call the constructor!
Call the constructor!
Call the constructor!
Call the constructor!
Calling the destructor!
Calling the destructor!
Calling the destructor!
Calling the destructor!

C++ namespace

C++ namespace

Suppose a situation where, when there are two students named Zara in a class, in order to clearly distinguish them, we have to use some additional information besides the name, such as their home address, or their parents' name etc.

The same situation occurs in C++ applications. For example, you might write a function called xyz(), and an identical function xyz() exists in another available library. This way, the compiler cannot tell which xyz() function you are using.

Therefore, the concept of namespace is introduced , which is specially used to solve the above problems. It can be used as additional information to distinguish functions, classes, variables, etc. with the same name in different libraries. Using a namespace defines a context. Essentially, a namespace defines a scope.

define namespace

A namespace is defined using the keyword  namespace followed by the name of the namespace, as follows:

namespace namespace_name {
   // code statement
}

In order to call a function or variable with a namespace, it needs to be preceded by the name of the namespace, like this:

name::code; // code can be a variable or a function

Let's see how namespaces define scope for entities like variables or functions:

#include <iostream>
using namespace std;

// 第一个命名空间
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二个命名空间
namespace second_space{
   void func(){
      cout << "Inside second_space" << endl;
   }
}
int main ()
{
 
   // 调用第一个命名空间中的函数
   first_space::func();
   
   // 调用第二个命名空间中的函数
   second_space::func(); 

   return 0;
}

When the above code is compiled and executed, it produces the following result:

Inside first_space
Inside second_space

using directive

You can use  the using namespace  directive so that you can use a namespace without prefixing it with the name of the namespace. This directive tells the compiler that subsequent code will use the names in the specified namespace.

#include <iostream>
using namespace std;

// 第一个命名空间
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二个命名空间
namespace second_space{
   void func(){
      cout << "Inside second_space" << endl;
   }
}
using namespace first_space;
int main ()
{
 
   // 调用第一个命名空间中的函数
   func();
   
   return 0;
}

When the above code is compiled and executed, it produces the following result:

Inside first_space

The using directive can also be used to specify specific items within a namespace. For example, if you only intend to use the cout part of the std namespace, you can use the following statement:

using std::cout;

In the subsequent code, when using cout, you don’t need to add the namespace name as a prefix, but  other items in the std  namespace still need to add the namespace name as a prefix, as shown below:

#include <iostream>
using std::cout;

int main ()
{
 
   cout << "std::endl is used with std!" << std::endl;
   
   return 0;
}

When the above code is compiled and executed, it produces the following result:

std::endl is used with std!

Names introduced by a using  directive follow the normal scoping rules. Names   are visible from the beginning of the using directive until the end of the scope. At this point, entities of the same name defined outside the scope are hidden.

disjoint namespace

A namespace can be defined in several different sections, so a namespace is composed of several separately defined sections. The various components of a namespace can be spread across multiple files.

So, if a component of the namespace needs to request a name defined in another file, that name still needs to be declared. The following namespace definition can define a new namespace, or add new elements to an existing namespace:

namespace namespace_name {
   // code statement
}

nested namespace

Namespaces can be nested, you can define a namespace inside another namespace like this:

namespace namespace_name1 {
   // code statement
   namespace namespace_name2 {
      // code statement
   }
}

You can access members in nested namespaces by using the :: operator:

// Access members in namespace_name2
using namespace namespace_name1::namespace_name2;

// Access members in namespace:name1
using namespace namespace_name1;

In the above statement, if namespace_name1 is used, the elements in namespace_name2 are also available in this scope, as follows:

#include <iostream>
using namespace std;

// 第一个命名空间
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
   // 第二个命名空间
   namespace second_space{
      void func(){
         cout << "Inside second_space" << endl;
      }
   }
}
using namespace first_space::second_space;
int main ()
{
 
   // 调用第二个命名空间中的函数
   func();
   
   return 0;
}

When the above code is compiled and executed, it produces the following result:

Inside second_space

おすすめ

転載: blog.csdn.net/m0_69824302/article/details/130295542