I was working on a Binary Class that uses Three-State Booleans to create measurable (size-wise) arrays of boolean strings that could be translated into morse code (TRUE = dash, FALSE = dot). I am using Arduino IDE (meaning I can't use anything for the std namespace) and a circuit with LEDs to test the morse code, but I will occasionally use Visual Studio 2022 to help debug issues. The problems started to come when I declared a Binary Object variable, then assigned at a constructor, and then used an overloaded assignment operator. The details Microsoft Visual Studio gave me are:
"A breakpoint instruction (__debugbreak() statement or a similar call) was executed in ConsoleApplication1.exe."
I copied the error details into my search bar and read other forum posts about this (including one of from here, Stack Overflow). What I found the issue to be was delete[] triboolList
in the Assignment Operator Overload function.
void Binary::operator=(tribool newElement) { //For reference, triboolList is of tribool Type
//The tribool type is defined as: enum tribool{DELIM=-1, FALSE, TRUE};
delete[] triboolList; //This is the problematic line
if (newElement == DELIM) {
triboolList = new tribool(DELIM);
}
else {
triboolList = new tribool[2];
triboolList[0] = newElement;
triboolList[1] = DELIM;
}
}
When I commented out the problematic line, the code began working again. Here is my main function in case anyone was curious:
Binary code;
tribool test[5] = { FALSE,TRUE,FALSE,FALSE,DELIM };
code = Binary(test); //Parameter Construction
std::cout << code << std::endl;
//morse(code); //Functions used in the Arduino IDE that I couldn't port over to Visual Studio
//morse(code);
code = TRUE; //This line causes the Breakpoint Instruction Executed error
code += TRUE;
code += TRUE;
//morse(code, 1); //Arduino IDE custom function that can't be tested on Visual Studio
std::cout << code << std::endl;
I know that getting rid of the problematic line fixes my issues, but I am afraid it is also wasting memory addresses. Are my concerns anything major, or am I just overreacting? (In case anyone was curious, my class does have a destructor that is just delete[] triboolList;
)
Upon hearing about the rule of 3s, I will also be sharing my Copy Constructor and Copy Assignment Operator:
Binary::Binary(const Binary& copyBinary) { //Copy Constructor
triboolList = new tribool[triLength(copyBinary.triboolList) + 1];
for (int i = 0; i < (int) triLength(copyBinary.triboolList); i++) {
triboolList[i] = (const tribool)copyBinary.triboolList[i];
}
triboolList[triLength(copyBinary.triboolList)] = DELIM;
}
Binary& Binary::operator=(const Binary& copyBinary) { //Copy Assignment Operator
delete[] triboolList;
triboolList = copyBinary.triboolList;
return *this;
}
Your assignment operator does not check for self-assignment, plus will have a double-free error since you are simply copying the pointer value between objects.
Instead of this, the copy/swap idiom can be used.
Since you state that Arduino does not have std::swap
, it should be easily implemented using the following:
Binary& Binary::operator=(Binary copyBinary)
{
tribool* temp = triboolList;
triboolList = copyBinary.triboolList;
copyBinary.triboolList = temp;
return *this;
}
This should be equivalent to the following, if std::swap
existed:
#include <algorithm>
//...
Binary& Binary::operator=(Binary copyBinary)
{
std::swap(triboolList, copyBinary.triboolList);
return *this;
}
If there are member variables other than triboolList
, they also have to be swapped with the passed-in members. I am assuming that triboolList
is the only member variable.