Basic Concept of Memory Management in a C++ Class

Have you ever paid attention to memory management when using classes? I have an elementary quiz about the basic concept of memory management in standard C++. This quiz is from my teaching experience because I found many programmers usually make the same mistake.

Now, take a look at the quiz. Please don't worry if you cannot give a answer. Paying attention to such code from now on is the most important thing you need to learn.

Quiz

How does the following code work?

What will happen during the running process? Why?

If there is a problem, how will you solve it?

class A
{
private:
   char* pchTest;
public:
   explicit A(char* const pchInitialText);
   virtual ~A();
   char* GetContent(void)const{return pchTest;}
};

A::A(char* const pchInitialText)
{
   pchTest = new char[strlen(pchInitialText)+1];
   strcpy(pchTest,pchInitialText);
}

A::~A()
{
   delete [] pchTest;
   pchTest = NULL;
}

void show(A clsAtest)
{
   printf("%s",clsAtest.GetContent());
}

int main(void)
{
   A Atest("Just Test!");
   show(Atest);
   return 0;
}

Hints

How is the parameter transferred into the functions as shown below?

void FunctionName(ValueType  para);
void FunctionName(ValueType *para);
void FunctionName(ValueType &para);

Have any idea? I will share my thoughts on the next page.

Basic Concept of Memory Management in a C++ Class

My Answer

First, let me explain the differences among the functions shown in the hints as on the last page:

  • For FunctionName(ValueType para), any value will be copied at first, and the copy is the real object accessed in the function. The original value would never be changed. The copy will be removed after the function ends.
  • For FunctionName(ValueType *para), the pointer will be copied at first. The copy pointer will be accessed in the function. The original value might be changed via the copy pointer. The copy pointer will be removed after the function ends, but the referred value won't be removed. For something like FunctionName(ValueType para), only the COPY will be removed.
  • For FunctionName(ValueType &para), no copying is done. The original object will be accessed directly in the function.

Now, let me go through the quiz code.

In main(), constructor A() is called; the pchTest member value of the Atest object is "Just Test!". Then, the Atest object is copied as clsAtest by the default copy constructor whenever the show() function is being called. The default constructor will copy only the value without allocating any memory automatically. That is, it will, by default, copy the value of Atest.pchTest to clsAtest.pchTest. Now, clsAtest.pchTest and Atest.pchTest point to the same memory. Then, the process displays "Just Test!" and clsAtest is removed at the end of show(), of course. So, the ~A() destructor is called.

Do you see the problem? The clsAtest.pchTest is deleted, and so is the memory that clsAtest.pchTest points to; that is also referred to by Atest.pchTest, but Atest is still alive! Now, Atest.pchTest actually points to an invalid memory! When the process exits main(), Atest will be deleted; the memory refered by Atest.pchTest will be deleted again. A memory error has occurred.

I think you might have some solutions now. Here, I share my three solutions; two are temporary solutions and one is a permanent cure.

Temporary solution 1: Use a pointer

void show(A *clsAtest)
{
   printf("%s",clsAtest->GetContent());
}

void main()
{
   A Atest("Just Test!");
   show(&Atest);
   return 0;
}

A pointer that refers to the Atest object will be copied; call it pAtest. Then, pAtest is accessed in show(). pAtest will be removed later, but the memory referred to by pAtest won't be deleted. Atest.pchTest still keeps the valid memory.

Temporary solution 2: Use a reference

void show(A &clsAtest)
{
   printf("%s",clsAtest.GetContent());
}

void main()
{
   A Atest("Just Test!");
   show(Atest);
 return 0;
}

This solution neither copies before entering the functions nor removes when the function ends. The process accesses the Atest object itself in the functions. If you don't want to modify any member value, use const, as shown below:

void show(const A & clsAtest)

Permanent cure

First, add a copy constructor:

A::A(const A &SourceA)
{
   pchTest = new char[strlen(SourceA.pchTest)+1];
   strcpy(pchTest,SourceA.pchTest);
}

When the process copies Atest, a copy constructor will be called so that cpA has its own pointer (cpA.pchTest), and its own memory referred to by cpA.pchTest. When the process exits show(), it deletes the memory that belongs to cpA, but not to Atest. No matter which kind of function has been called, no system error would occurr.

The same resource management issues will also occur in an assignment; for example:

void main()
{
   A Atest("Just Test!");
   A Atest2("Test Again!");
   Atest = Atest2;
   show(Atest);
   return 0;
}

Thus, you need to override the assignment operator:

A& A::operator= (const A &SourceA)
{
   if( this != &SourceA )
   {
      delete [] pchText;
      pchText = new char[strlen(SourceA.pchText)+1];
      strcpy(pchText,SourceA.pchText);
   }
   return *this;
}

The entire permanent cure code is on the next page.

Basic Concept of Memory Management in a C++ Class

#include <string.h>

class A
{
private:
   char* pchText;

public:
   explicit A(char* const pchInitialText);
   virtual ~A();
   A(const A &SourceA);
   A& operator= (const A &SourceA);

   char* GetContent(void)const{return pchText;}
};

A::A(char* const pchInitialText)
{
   pchText = new char[strlen(pchInitialText)+1];
   strcpy(pchText,pchInitialText);
}

A::~A()
{
   delete [] pchText;
   pchText = NULL;
}

A::A(const A &SourceA)
{
   pchText = new char[strlen(SourceA.pchText)+1];
   strcpy(pchText,SourceA.pchText);
}

A& A::operator= (const A &SourceA)
{
   if( this != &SourceA )
   {
      delete [] pchText;
      pchText = new char[strlen(SourceA.pchText)+1];
      strcpy(pchText,SourceA.pchText);
   }
   return *this;
}

void show(A clsAtest)
{
   printf("%s",clsAtest.GetContent());
}

int main(void)
{
   A Atest("Just Test");
   show(Atest);
   return 0;
}

Thank you for reading patiently. I hope this helps.

References



About the Author

Reta Pan

A R&D Software Engineer in Taiwan.
International High IQ Society Member, New York.
MCSD(Microsoft Certified Solution Developer (for Microsoft .NET))
Web Site: Anpino's Circle
English is not my primary language, I will be glad to receive your response, especially the advises that you can provide regarding my poor English.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 19, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT You deployed your app with the Bluemix PaaS and it's gaining some serious traction, so it's time to make some tweaks. Did you design your application in a way that it can scale in the cloud? Were you even thinking about the cloud when you built the app? If not, chances are your app is going to break. Check out this upcoming webcast to learn various techniques for designing applications that will scale successfully in Bluemix, for the …

  • Live Event Date: September 19, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT In response to the rising number of data breaches and the regulatory and legal impact that can occur as a result of these incidents, leading analysts at Forrester Research have developed five important design principles that will help security professionals reduce their attack surface and mitigate vulnerabilities. Check out this upcoming eSeminar and join Chris Sherman of Forrester Research to learn how to deal with the influx of new device …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds