Hi,

I keep getting an error in Visual Studio C++. I am trying to create a copy constructor but keep getting this error.

"Windows has triggered a breakpoint in test.exe.
This may be due to a corruption of the heap, and indicates a bug in test.exe or any of the DLLs it has loaded."

After going thru the debugger I found the problem on a delete [] that I do.

Here is a simplified version of my code. I have a couple classes in my header file(I know this is bad design but for now I just want to understand what is going wrong).

Test.h //header file
class StringValues
{
public:
StringValues();
~StringValues();
char *Name;
char *Message;
}

class Tblk
{
public:
Tblk();
~Tblk();
private:
StringValues myStringValues;
}

Here is my cpp file.

Tblk::Tblk()
{
//constructor
}

Tblk::~Tblk
{
//destructor
}

Tblk::Tblk(const Tblk& other)
{
strncpy(myStringValues.Name, other.myStringValues.Name, 100);
strncpy(myStringValues.Message, other.myStringValues.Message, 100);
}

StringValues::StringValues()
{
	Name = new char[MAXCOMMENTSTRING];
	Message = new char[MAXCOMMENTSTRING];
}

StringValues::~StringValues()
{
delete [] Name;  ===Error here
delete [] Message;
}

In my main file I have.....

void main()
{
   Tblk A;
    Tblk B = A;  
}

When I run the code thru the debugger object B gets destroyed and then myStringValues destructor is called. This is where I get an error. When I get to "delete [] Name" I get the error message that there may be a corruption of the heap. This seems like it should work. I allocated dynamic memory on the heap in the StringValues constructor and delete it in the destructor. Can anyone tell me why this doesn't work????

Dani AI

Generated

Short answer: the crash is classic heap corruption caused by incorrect ownership/copy semantics — either a double-delete or a write past an allocated buffer. The important subtlety missing from some replies is initialization order: when a Tblk is copy-constructed, its member myStringValues is itself copy-constructed before the body of Tblk::Tblk(const Tblk&) runs. If StringValues relies on the compiler-generated copy (shallow copy of the char* members), both objects end up owning the same pointers and both destructors call delete[] on the same address.

was right to call out shallow copying, and ’s advice to use std::string is the most robust fix. Replacing the raw pointers removes all of the manual ownership work:

struct StringValues { 
  std::string Name; 
  std::string Message; 
};

If raw buffers must be used, follow the Rule of Three: provide a proper destructor, copy-constructor and copy-assignment that allocate separate buffers and copy contents, or else force default construction of the member before copying in Tblk’s initializer list so you don’t end up with two objects sharing pointers:

Tblk::Tblk(const Tblk& other) : myStringValues()  // force default construction
{
  // copy content safely into newly allocated buffers
}

Practical checklist to resolve the problem: (1) Prefer std::string; (2) If using char* implement deep-copy and operator= correctly; (3) avoid magic numbers and ensure null-termination (strncpy can leave no terminator); (4) run a Debug build, put breakpoints in constructors/destructors and watch the pointer addresses — identical addresses indicate shared ownership/double-delete. ’s note about operator= is useful for assignments (not initialization); make sure you’re handling both copy-construction and assignment.

Recommended Answers

All 5 Replies

since this is c++ why use pointers? Just make name and message both std::string and that will probably solve the memory leek problemn.

commented: Thanks for all your help. You are da man! +1

I think what is happening is this

Tblk A;
 Tblk B = A;

This is using a default copy constructor since you haven't defined one, and both your objects A and B are pointing to the same set of strings.

So when you leave main, both A and B will be destroyed, but once you destroy A and delete the pointers, when B's destructor is called, you have no valid pointer values to destroy. Hope that makes sense.

And as Ancient Dragon said you should use strings, and declare a copy constructor explicitly in order to avoid such situations.

I actually created a copy constructor, so I wouldn't have that exact problem that you mentioned. I dont know if the issue is with the copy constructor that I used. I probably should just try this by using the string class, but am just curious for further knowledge why my implementation won't work. This was the copy constructor that I had.

Tblk::Tblk(const Tblk& other)
{
strncpy(myStringValues.Name, other.myStringValues.Name, 100);
strncpy(myStringValues.Message, other.myStringValues.Message, 100);
}

your implementation doesn't work because it doesn't allocate memory for the two strings. Here is one way to implement it

const int MAXCOMMENTSTRING = 255;
class StringValues
{
public:
    StringValues()
    {
        Initialize();
    }
    StringValues(StringValues& s)
    {
        Initialize();
        strcpy(Name,s.Name);
        strcpy(Message,s.Message);
    }
    ~StringValues()
    {
        delete[] Name;
        delete[] Message;
    }
    char *Name;
    char *Message;
private:
    void Initialize()
    {
        Name = new char[MAXCOMMENTSTRING];
        Message = new char[MAXCOMMENTSTRING];
        memset(Name,0,MAXCOMMENTSTRING);  // optional
        memset(Message,0,MAXCOMMENTSTRING); // optional
    }
};

When you leverage off of the = operator without an overloaded ooperator=() implemented, the compiler uses a predefined method of copying the data by doing a direct member to member copy. Since you are using pointers as members, the addresses of the pointers are being copied, rather than firing the copy constructor that you have written. The easiest way to fix this would be to implement an overloaded = operator like this:

//add this to the public part of the header
Tblk & operator=(Tblk const &);

//implement it in the .cpp like this:
Tblk & Tblk::operator=(Tblk const & rhs)
{
    strncpy(myStringValues.Name, rhs.myStringValues.Name, 100);
    strncpy(myStringValues.Message, rhs.myStringValues.Message, 100);
    return *this;
}
commented: Thanks for your help! +1
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.