C++ - overloaded assignment operator memory leaks - c++

I have a class method that works with a copy of an object (*this, to be exact). The leaks occur within the overloaded assignment operator - that's what Visual Leak Detector says, anyway. What I'm doing is working with copy and if the work done is satisfactory I copy that newly created object back. I've also implemented a custom destructor, copy constructor and assignment operator because the problem occurs with dynamically allocated memory, obviously. My experience with C++ is quite limited so there could be some evil stuff in the code.
I will provide more info if needed.
Problematic method:
bool Grid::SurroundShipSquares(int top, int bottom, int left, int right)
{
// copying itself
Grid gridCopy(*this);
Square** squaresCopy = gridCopy.GetSquares();
for (int i = top; i <= bottom; ++i)
{
for (int j = left; j <= right; ++j)
{
if (squaresCopy[i][j].GetState() != SquareState::Vacant)
return false;
(squaresCopy[i][j]).SetState(SquareState::Unoccupiable);
}
}
// the problem occurs here
*this = gridCopy;
return true;
}
Copy constructor:
Grid::Grid(const Grid& source)
{
_position = source._position;
_size = source._size;
int dimensions = static_cast<int>(_size);
_squares = new Square*[dimensions];
for (int i = 0; i < dimensions; ++i)
{
_squares[i] = new Square[dimensions];
for (int j = 0; j < dimensions; ++j)
{
_squares[i][j] = source._squares[i][j];
}
}
}
Assignment operator:
Grid& Grid::operator=(const Grid& source)
{
if (this == &source)
return *this;
_position = source._position;
_size = source._size;
int dimensions = static_cast<int>(_size);
_squares = new Square*[dimensions];
for (int i = 0; i < dimensions; ++i)
{
_squares[i] = new Square[dimensions];
for (int j = 0; j < dimensions; ++j)
{
_squares[i][j] = source._squares[i][j];
}
}
return *this;
}
Destructor:
Grid::~Grid()
{
int dimensions = static_cast<int>(_size);
for (int i = 0; i < dimensions; ++i)
{
delete[] _squares[i];
}
delete[] _squares;
}

The problem with your code is that you manage all your resources manually. This is terribly unsafe and a massive headache to do correctly, as is aptly demonstrated by both the existing answers being wrong.
Use std::vector. This class will automatically manage all the memory for you, freeing you from having to do it yourself. This will greatly simplify your code, as well as making it correct.
Also, self-assignment checking is an ancient anti-pattern. Do not include a check for self-assignment. If your assignment operator (you shouldn't really need to write your own with std::vector-based memory management in most cases) cannot handle self-assignment without a special case, it is broken.

Related

How do I prevent this buffer overrun?

I'm writing a class which deals with polynomials of an arbitrary size, and when overloading the * operator I have a buffer overrun warning that I don't know how to deal with.
Polynomial Polynomial::operator*(const Polynomial& rhs)
{
int returnSize = (this->size + rhs.getSize()) - 1;
int* returnArray = new int[returnSize];
for (int i = 0; i < this->size; i++)
{
for (int j = 0; j < rhs.getSize(); j++)
{
returnArray[i + j] = this->polynomial[i] * rhs.polynomial[j];
}
}
}
And I think that by the nature of the program that it isn't actually possible to get buffer overrun, but I don't understand it very well so I'm probably mistaken. The warning states:
C6386: Buffer Overrun whilst writing to 'returnArray': the writable size is 'returnSize*4' bytes, but'8' bytes might be written.
I'm also having this issue with the copy constructor.
Polynomial::Polynomial(const Polynomial& rhs)
{
this->size = rhs.getSize();
this->polynomial = new int[rhs.getSize()];
for (int i = 0; i < rhs.getSize(); i++)
{
this->polynomial[i] = rhs.polynomial[i];
}
}
I really hope this isn't a daft question, and thanks for your help!
The warning is caused because the compiler doesn't know the value of returnSize at compile time, and assumes it may be less than 2. You can easily remove this warning by assigning space for at least two int values in your new call:
int* returnArray = new int[std::max(returnSize,2)]; // Need #include <algorithm> for std::max

operator = overload in template class

Im working on matrix template class, and now i should write the "=" operator overload.
What Im trying to do is to delete the matrix that appears in the left side of the '=', and return new one that equals to the matrix that appears in the right side of the '='.
because i can't delete "this" with a distructor, I delete it "manually" in the function. but now i should make a new matrix, therefor i make a new one ("temp") and return it.
The prblem is that "temp" is really return, but it doesn't set in the matrix that appears in the left side of the '='.
The code:
Matrix<int> m (3, 4);
Matrix<int> m2(2, 5);
m2 = m;
This was the main part.
The function:
template<class T>
Matrix<T> & Matrix<T>::operator=(Matrix<T>& mat)
{
if (this==&mat)
{
return *this;
}
for (int i = 0; i < this->rows; i++)
{
delete[] this->mat[i];
}
delete[] this->mat;
Matrix<T> * temp = new Matrix<T>(mat.rows, mat.cols);
for (int i = 0; i < temp->rows; i++)
for (int j = 0; j < temp->cols; j++)
{
temp->mat[i][j] = mat.mat[i][j];
}
return *temp;
}
template<class T>
Matrix<T>::Matrix(int row, int col)
{
rows = row;
cols = col;
mat = new T*[rows];
for (int i = 0; i < rows; i++)
{
mat[i] = new T[cols];
}
rester(*this);
}
Thx!!
Use std::vector as storage (instead of manal new and delete), and just accept the copy assignment operator generated by the compiler. It's that easy.
If you absolutely want to implement the copy assignment yourself, for learning, then just express copy assignment in terms of copy construction.
To do that, first define a noexcept swap operation:
// In class definition:
friend
void swap( Matrix& a, Matrix& b )
noexcept
{
using std::swap;
// swap all data members here
}
Then the copy assignment operator can be expressed as simply
// In class definition
auto operator=( Matrix other )
-> Matrix&
{
swap( *this, other );
return *this;
}
It's popular, an idiom, because it's very simple yet exception safe.
Instead of returning a reference, which adds verbosity and some possible marginal inefficiency for no gain, you might want to just use void as return type. However, probably for historical reasons, the containers in the standard library require the copy assignment operator to return a reference to self.
You need to allocate memory for this instead of creating a temp.
template<class T>
Matrix<T> & Matrix<T>::operator=(Matrix<T>& rhs)
{
if (this==&rhs)
{
return *this;
}
// Delete current memory
for (int i = 0; i < this->rows; i++)
{
delete[] this->mat[i];
}
delete[] this->mat;
this->rows = rhs.rows;
this->cols = rhs.cols;
// Allocate new memory
// Assign values to newly allocated memory.
this->mat = new int*[rhs.rows];
for (int = 0; i < rhs.rows; ++i )
{
this->mat[i] = new int[rhs.cols];
for (int j = 0; j < rhs.cols; j++)
{
this->mat[i][j] = rhs.mat[i][j];
}
}
// Return *this.
return *this;
}
I would recommend using the suggestion given in the answer by #Cheersandhth.
Also use a different name of the argument. Don't confuse with the member variable mat and the argument mat.

munmap_chunk(): invalid pointer in C++ program

I get an error "munmap_chunk(): invalid pointer", I don't know why. Problem appears when I use MultipliedByMatrix method. It can't properly delete the matrix that was created in this method.
#include "matrix.h"
Matrix::Matrix(int matr_size) {
size = matr_size;
Matr = new int *[size];
for(int i = 0; i < size; i++)
Matr[i] = new int[size];
for(int i = 0 ; i < size; i++)
for(int j = 0; j < size; j++)
Matr[i][j] = rand() % 100;
std::cout << "New matrix is created" << std::endl;
}
Matrix::~Matrix() {
for(int i = 0; i < size; i++)
delete[] Matr[i];
delete[] Matr;
Matr = NULL;
std::cout << "Matrix is deleted" << std::endl;
}
Matrix Matrix::MultipliedByMatrix(Matrix OtherMatr) {
Matrix new_matr = Matrix(this->GetSize());
int new_value;
for(int i = 0 ; i < size; i++)
for(int j = 0; j < size; j++) {
new_value = 0;
new_value += Matr[j][i] * OtherMatr.GetValue(i, j);
new_matr.SetValue(i, j, new_value);
}
return new_matr;
}
int Matrix::GetSize() {
return size;
}
int Matrix::GetValue(int i, int j) {
return Matr[i][j];
}
void Matrix::SetValue(int i, int j, int value) {
Matr[i][j] = value;
}
Did you write the Matrix class yourself? If so, I bet the problem is that you don't have a copy or move constructor. If so, the compiler will have generated one for you. This will copy the values of size and Matr but it won't create copies of the pointed-to arrays. When you write:
return new_matr;
this creates a new matrix (using the copy constructor - which just copies the pointer), and then calls the destructor of new_matr (which deletes the memory which is pointed to). The calling function is then dealing with junk memory, and when it tries to eventually delete the result, all hell will break loose
You also will need to write a move assignment operator.
Alternatively make Matr a std::vector<int> (of length 'size' squared), and write:
int Matrix::GetValue(int i, int j) {
return Matr[i*size+j];
}
(and similarly for other functions). std::vector has a proper copy and move constructor, and proper assignment behaviour - so it will all just work. (It will also be a lot faster - you save a whole pointer indirection.)
This is not an analytical answer to the question but a piece of advice with respect to solving (or better circumventing) the problem.
Avoid memory handling on your own if you can. (And it is very likely that you actually can avoid it.)
You can read my answer on the question "1D or 2D array, what's faster?" to get a lengthy explenation why it is probably undesirable to use the kind of memory layout you're using.
Furthermore, you'll find an (yet untested) example of how to implement a simple matrix container on top of std::vector.
You can look at the scheme and try to implement your own if you want. The design has several advantages compared to your implementation:
It is templated and thus usable with int as well as many other types.
Conformance to the standard container concept is achieved easily.
No destructor / copy constructor / move constructor or assignment operators required: std::vector is handling the resources and does the "dirty work" for you.
If you still want to use your RAW-Pointer approach (for academic purposes or something):
Read What is meant by Resource Acquisition is Initialization (RAII)? and try to understand the answers.
Read What is The Rule of Three? properly and make sure you have implemented (preferably obeying the RAII concept) those functions:
copy constructor,
destructor,
assignment operator and if desired
move constructor and
move assignment operator.
Still read my answer to the "1D or 2D array, what's faster?" question to see how you would want to organize your allocations in order to be exception safe in case of std::bad_alloc.
Example: Your constructor the 'a little better' way:
Matrix::Matrix(std::size_t const matr_size) // you have a size here, no sign required
{
Matr = new int*[matr_size];
std::size_t allocs(0U);
try
{ // try block doing further allocations
for (std::size_t i = 0; i < matr_size; ++i)
{
Matr[i] = new int[matr_size]; // allocate
++allocs; // advance counter if no exception occured
for(std::size_t j = 0; j < matr_size; j++)
{
Matr[i][j] = rand() % 100;
}
}
}
catch (std::bad_alloc & be)
{ // if an exception occurs we need to free out memory
for (size_t i = 0; i < allocs; ++i) delete[] Matr[i]; // free all alloced rows
delete[] Matr; // free Matr
throw; // rethrow bad_alloc
}
}

Segfault in custom string class

So I am trying to complete this very basic string class (MyString). Everything seemed to work, but when I uploaded it to the assignment site, it showed a segfault. The upload site uses electric fence, but it didn't give much insight as to where the fault occurred. It essentially runs through each function and returns a pass/fail/fault for it. In the case of the getline function, it returned a fault.
Also, the upload site uses valgrind which reported no errors.
EDIT: I almost forgot, when I called the function in the driver, it read from a file messages.txt, which contained one line of text: Testing this program... PLEASE WORK
Below is the getline function (as it exists in the implementation file) that appears to be the source of the fault:
// reads line from istream ... line end at newline char of choice) -- '\n' in this case
void MyString::getline(istream &inFile, char delimit)
{
int index = 0;
do
{
data[index] = inFile.get();
index ++;
if (index + 1 > capacity)
{
MyString tempStr;
delete [] tempStr.data;
tempStr.data = new char [capacity];
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
capacity += 5;
size = index;
delete [] data;
data = new char [capacity];
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
delete [] tempStr.data;
tempStr.data = NULL;
}
}
while (!inFile.eof() && data[index-1] != delimit);
if (data[index - 1] == delimit)
{
index -= 1;
if (static_cast<double>(index)/capacity < .25 && capacity > 5)
{
capacity -= 5;
char *temp = new char [capacity];
for (int i = 0; i < index; i++)
{
temp[i] = data[i];
}
delete [] data;
data = temp;
}
}
data[index] = '\0';
size = index + 1;
}
I feel like it's either something very simple I overlooked or a fundamental flaw in the way I approached this particular function. Any help is appreciated. I'm very new to programming (few weeks in) and am just trying to stay afloat -- got enrolled in CompSci 1 + 2 simultaneously.
Additionally, below is more of the implementation file -- particularly, the constructors (minus copy) and a few overloaded operators. While I could compile it on my end and concatenate class objects successfully, the upload site returned a fail when it tested "Concatenation." There wasn't any feedback as to which operator failed. I was curious what might cause that in my code. Thanks again.
#include <iostream>
#include <fstream>
#include "MyString.h"
using namespace std;
//default constructor - works
MyString::MyString()
{
capacity = 5;
size = 0;
data = new char [capacity];
}
// constructor with character string
MyString::MyString(const char *cString)
{
int index = 0;
capacity = 5;
while ( cString[index] != '\0')
{
index++;
}
size = index + 1;
while (size > capacity)
{
capacity += 5;
}
data = new char[capacity];
for (int i = 0; i < size; i++)
{
data[i] = cString[i];
}
}
// copy constructor
MyString::MyString(const MyString &aMyString)
{
capacity = aMyString.capacity;
size = aMyString.size;
data = new char [capacity];
for (int i = 0; i < size; i++)
{
data[i] = aMyString.data[i];
}
}
// overloaded += operator
void MyString::operator+=(const MyString &aMyString)
{
int tSize1 = size;
int holder = 0;
size += aMyString.size - 1;
while (size > capacity)
{
capacity += 5;
}
char *tempArr = new char [capacity];
for (int i = 0; i < (tSize1 - 1); i ++)
{
tempArr[i] = data[i];
}
for (int i = (tSize1 - 1); i < size; i++)
{
tempArr[i] = aMyString.data[holder];
holder ++;
}
delete [] data;
data = tempArr;
}
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString) const
{
int holder = 0;
MyString tempS;
int tSize1 = size + aMyString.size - 1;
int tCap1 = capacity + aMyString.capacity;
if (static_cast<double>(tSize1)/tCap1 < .25 && tCap1 > 5)
{
tCap1 -= 5;
}
tempS.size = tSize1;
tempS.capacity = tCap1;
delete [] tempS.data;
tempS.data = new char [tempS.capacity];
for (int i = 0; i < (size - 1); i ++)
{
tempS.data[i] = data[i];
}
for (int i = (size - 1); i < tSize1; i++)
{
tempS.data[i] = aMyString.data[holder];
holder ++;
}
return tempS;
}
I don't know if these are all your bugs but I see two that stand out from the code:
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
[snip]
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
Both the for statements are accessing one more character than they should. If you want to process something 5 times for example in zero based indexing you check for i < 5 not i <= 5 . If I am not mistaken you have made that error in both these for loops. I believe they should be:
for (int i = 0; i < index; i++)
and
for (int i = 0; i < size; i++)
Writing memory beyond the edge of your arrays can cause problems like the segfaults.
Right away, the problem is your operator +=. It's supposed to return a reference to the object, not void.
Second, operator + should be written in terms of operator +=. Instead you wrote the whole operator + "from scratch", duplicating the code in operator +=
Here is how operator+ should be implemented:
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString)
{
MyString result = *this; // copy the object
result += aMyString; // call the operator += (where the real work is done).
return result; // just return the result
}
Your operator+=, needs to be defined as this:
MyString& MyString::operator+(const MyString &aMyString)
{
// code to do work
return *this;
}
Third, you failed to implement an assignment operator. You implemented the copy constructor, but not the assignment operator. Unless you didn't post it, it has to be implemented if you want to assign one string to another.
Last, your operator+= has a flaw. It changes the value of size here:
size += aMyString.size - 1;
Then attempts to allocate memory. What if that memory allocation fails (new throws an exception)? How do you "rollback" the value of size to its original value? You can't, at least not with your implementation.
To summarize, just because you have your implementation "working" doesn't mean it really is working properly. The things I pointed out above (no assignment operator, and operator += not returning a reference, *this) are just two issues.
The problem with assignments like this is that it can give you the false sense of accomplishment, when truthfully, what you have coded has bugs you never realized, but worse, can be easily created. For example:
int main()
{
MyString s("abc");
MyString t("123");
s = t;
}
Without an assignment operator, that code fails due to a memory leak and a double deletion error.
It really takes an intermediate to advanced programmer to create yes, something that sounds simple as a "String" class properly, at least one that can pass all the tests that would make a String class usable in a real program.

Assigning and Deleting Pointers

Okay, so here's the context. I've been up for almost a day straight now working on the legendary 8-puzzle problem. I have my heuristics down and my A_star algorithm down. We are required by the project spec to solve it using three different heuristic values. I can solve it for any one of the three individually, but when I go to solve them in succession, I get a ridiculous loop, and it never finds the correct successor state.
I believe my problem is with my pointers. I have a class, State, as defined below that has an int** array and a pointer to a State (its parent).
EDIT: I have to use int** as defined by the project specification, otherwise I would gladly use a pointer.
State (int **bd, State* prnt);
State (const State& other);
~State ();
I am then declaring them as such:
State::State(int **bd, State* prnt) {
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
}
// fill in the board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = bd[i][j];
//board[i][j] =
}
}
// set the parent
parent = prnt;
}
State::State(const State& other) {
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
State::~State() {
//std::cout << "Deconstructing " << this << endl;
for (int i = 0; i < 3; i++)
delete board[i];
delete [] board;
delete parent;
parent = other.parent;
}
State::~State() {
//std::cout << "Deconstructing " << this << endl;
for (int i = 0; i < 3; i++)
delete board[i];
delete [] board;
delete parent;
}
State& State::operator=(const State &rhs) {
if (&rhs == this) {
return *this;
}
for (int i = 0; i < 3; i++) {
delete board[i];
}
delete [] board;
// allocate the board
board = new int*[3];
for (int i = 0; i < 3; i++) {
board[i] = new int[3];
}
// fill in the board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//board[i][j] = rhs.board[i][j];
board[i][j] = rhs.getIntAtCoor(j, i);
}
}
//delete parent;
// set the parent
parent = rhs.parent;
// set g
g = rhs.g;
f = rhs.f;
hType = rhs.hType;
return *this;
}
I don't give the exact declarations -- some of it is simple like int = int. I just can't quite figure it out. I feel like either my delete parent is wrong or my parent = other.parent is wrong (or both).
Thank you for your time and help,
Tyler
Upgrading your code-style may force the errors to evaporate. In other words new and delete are error prone and should be avoided when better alternative exists.
For management of the cells consider:
std::shared_ptr: can be used to void the delete calls
std::vector can be used to avoid the new and delete calls
Note you should use it like std::vector<int> board( 3 * 3 ) and board.at( x + y * 3 ).
And best of all just use a static array int board[3][3]. No allocation at all.
Also child states do not own their parent states. It's the other way around. So child states shouldn't delete their parents. You can still safely keep a parent pointer, but make sure you cleanup the children before you allow a parent to go out of scope (deleted or otherwise). All of this cleaning and deleting doesn't neccessarily involve new at all. Your State class looks small enough that is doesn't matter if they are copied by value. In which case just have the parent use a std::vector<State> m_children and the compiler will take care of the rest.
You don't show the full definition of the copy constructor but I assume that the parent = other.parent line is in there. In that case, wouldn't the parent be responsible for its own lifetime and the delete parent in the destructor shouldn't exist at all.
Also note that you need to at least disable (private declaration) or implement the copy assignment operator.
Better still, use a vector of vector for your 2d array and let the language work for you.
Perhaps not a direct answer, but you are going against best practices for C++.
It's easier and definitely more maintainable to use vectors for this problem.
size_t row_sz = 3;
size_t col_sz = 3;
std::vector<int> board(row_sz * col_sz, 0);
int i = 0;
for (size_t r = 0; r < 0; r++)
for (size_t c = 0; c < 0; c++)
board[ r * row_sz + c ] = i++;
Multidimensional arrays are much easier handled with the above strategy as well. It just breaks less. If you really want the row/col access, write a wrapper around it.
struct Matrix {
int &operator()(size_t r, size_t c);
const int &operator()(size_t r, size_t c) const;
private:
std::vector<int> data;
};