Bad array new length error unhandled exception - c++

I am not sure where I am going wrong with this.
I have a Movie.h with all the data members and constructors destructors and copy constructors needed but I have a feeling it's failing at my assignment operator someone, please help
Movie& Movie::operator=(const Movie& _assign) {
// Self-assignment check
if (this == &_assign)
return *this;
// Shallow copy non-dynamic data members
mRuntime = _assign.mRuntime;
// Deep copy appropriate data members
mTitle = new char[strlen(_assign.mTitle) + 1];
strcpy_s(mTitle, strlen(_assign.mTitle) + 1, _assign.mTitle);
// Deep copy the reviews
SetStars(_assign.mStars, mNumReviews);
return *this;
}
void Movie::SetStars(const int* _stars, int _numReviews) {
// Allocate array and deep copy
mStars = new int[_numReviews];
for (int i = 0; i <= _numReviews; ++i) {
// Cap reviews between 1-10
if (_stars[i] > 10)
{
mStars[i] = 10;
}
else if (_stars[i] < 0)
{
mStars[i] = 0;
}
else
{
mStars[i] = _stars[i];
}
}
// Set the number of reviews
mNumReviews = _numReviews;
}

The problem happens here:
mStars = new int[_numReviews];
for (int i = 0; i <= _numReviews; ++i) {
Specifically here:
i <= _numReview // this causes you to go out of bounds
changing it to:
i < _numReview
resolves the issue
You are allocating _numReview items. C++ has 0-based array indexing. Elements will go from 0 to _numReview - 1
Please consider using std::string and std::vector instead of c-style arrays.

Related

Dynamic arrays in C++ compared to Java

Recently, I started to learn C++ after I have learned Java, and I was instructed to make a dynamic array, so I tried to make a temp variable which contains what I need and then reassign it into the variable I actually want to use.
void Pile::grow(Stone s){
Stone temp[getLength() + 1];
for (int i = 0; i < sizeof(temp) / sizeof(temp[0]); ++i) {
if (sizeof(temp) / sizeof(temp[0]) < 28){
temp[i] = stoneArr[i];
}
}
stoneArr = temp;
}
But the compiler is giving me an error that I cannot reassign it, for some reason I just can't understand.
void Pile::grow(Stone s)
You are not using s anywhere. Are you supposed to add it to the new array you are trying to create?
Stone temp[getLength() + 1];
This is not legal in standard C++. The size of a fixed array must be known at compile time.
Some compilers support "variable length arrays" as a non-standard extension, but do not rely on them if you need to write portable code. See Why aren't variable-length arrays part of the C++ standard?
To allocate an array dynamically at runtime, use the new[] operator instead, eg:
Stone *temp = new Stone[getLength() + 1];
...
delete[] temp;
Or, use the standard std::vector container instead, eg:
#include <vector>
std::vector<Stone> temp(getLength() + 1);
...
for (int i = 0; i < sizeof(temp) / sizeof(temp[0]); ++i)
You cannot use this sizeof trick on a dynamic array, let alone a VLA. sizeof is evaluated only at compile time, not at runtime.
Since you are copying values from an existing array, use the length of that array instead:
for (int i = 0; i < getLength(); ++i)
if (sizeof(temp) / sizeof(temp[0]) < 28)
Hard-coding a 28 here makes no sense. In fact, this whole if check needs to be removed completely.
stoneArr = temp;
This assignment will not work when temp is a VLA. And stoneArr can't be a VLA anyway.
stoneArr needs to be either a Stone* pointer to a new[]'d array (that is managed by following the Rule of 3/5/0), or a std::vector<Stone> (preferred).
With all of that said, try this instead:
private:
Stone *stoneArr;
int arrLength;
...
Pile::Pile()
: stoneArr(NULL), arrLength(0) {
}
Pile::Pile(const Pile &src)
: stoneArr(new Stone[src.arrLength]), arrLength(src.arrLength) {
for (int i = 0; i < arrLength; ++i) {
stoneArr[i] = src.stoneArr[i];
}
}
Pile::~Pile() {
delete[] StoneArr;
}
Pile& Pile::operator=(const Pile &rhs) {
if (&rhs != this) {
Pile temp(rhs);
std::swap(stoneArr, temp.stoneArr);
std::swap(arrLength, temp.arrLength);
}
return *this;
}
int Pile::getLength() const {
return arrLength;
}
void Pile::grow(const Stone &s){
Stone *temp = new Stone[arrLength + 1];
for (int i = 0; i < arrLength; ++i) {
temp[i] = stoneArr[i];
}
temp[arrLength] = s;
delete[] stoneArr;
stoneArr = temp;
++arrLength;
}
Or:
#include <vector>
private:
std::vector<Stone> stoneArr;
...
// std::vector follows the rule of 3/5/0, so let the
// compiler handle Pile(), Pile(const Pile &), ~Pile(),
// and operator= for you...
int Pile::getLength() const {
return stoneArr.size();
}
void Pile::grow(const Stone &s){
stoneArr.push_back(s);
}

C++ Deep copy of dynamic array through assignment operator

I am trying to copy a dynamically allocated array to an instance. My code seems to be copying the values over, but it also need to resize the array to match the "&other" size array.
A little info about the code: There are two classes at hand, one is "Movie" which takes a title, film-time, and director (all pointers) as private members. There is another called "MovieCollection" which is an array that stores each instance of "Movie" in a given index.
//These are private member variables:`
int ArrySize = 50; //There is another section of code that points to this and resizes if needed, I believe it needed a size at runtime though.
//Array to store instance of "movie"
Movie *movieArry = new Movie[ArrySize];
//This is assignment operator
const MovieCollection& operator=(const MovieCollection& other)
{
delete []movieArray;
int otherSizeArry = other.ArrySize;
Movie* temp;
temp = new Movie[otherSizeArry];
for (int i = 0; i < otherSizeArry; i++)
temp[i] = other.movieArry[i];
return *this;
delete []temp;
}
I used another function I wrote to resize the array while the instance is being created. For example, the instance I want to copy over has 10 indexes but the new instance I am trying to copy the values into still has a limit of 50. From what I understand I have to delete it because arrays cannot be resized, then copy the new size over (along with the values).
Any help would be greatly appreciated and thank you in advanced. Also, sorry if more code is required. I didn't want to give more than what was needed.
Your assignment operator is implemented incorrectly. It is freeing the movieArray array before allocating the new temp array. If the allocation fails, the class will be left in a bad state. And you are not assigning the temp array to movieArray before calling return *this; (the delete []temp is never reached, the compiler should have warned you about that).
The operator should look more like this instead:
MovieCollection& operator=(const MovieCollection& other)
{
if (&other != this)
{
int otherSizeArry = other.ArrySize;
Movie* temp = new Movie[otherSizeArry];
for (int i = 0; i < otherSizeArry; ++i) {
temp[i] = other.movieArry[i];
}
// alternatively:
// std::copy(other.movieArry, other.movieArry + otherSizeArry, temp);
std::swap(movieArray, temp);
ArrySize = otherSizeArry;
delete[] temp;
}
return *this;
}
If your class has a copy constructor (and it should - if it does not, you need to add one), the implementation of the assignment operator can be greatly simplified:
/*
MovieCollection(const MovieCollection& other)
{
ArrySize = other.ArrySize;
movieArray = new Movie[ArrySize];
for (int i = 0; i < ArrySize; ++i) {
movieArray[i] = other.movieArry[i];
}
// alternatively:
// std::copy(other.movieArry, other.movieArry + ArrySize, movieArray);
}
*/
MovieCollection& operator=(const MovieCollection& other)
{
if (&other != this)
{
MovieCollection temp(other);
std::swap(movieArray, temp.movieArray);
std::swap(ArrySize, temp.ArrySize);
}
return *this;
}

Destructor called after returning from function

I've got some project for my University and I need to perform converting some data from file to matrix representation.
The main problem is that after returning form "returnNeighbours(int node)" destructor is called on neighbours object(as I concluded from running gdb).
I know that destructor is always called when local variable, in function, is initialized, but neihbours is a class member. I won't post everything, because it's not necessary I think. I've got some structures listed below.
representation.cpp
NodeContainer::NodeContainer(){ size = 0; array = nullptr; }
NodeContainer::~NodeContainer(){ size = 0; delete[] array; }
void NodeContainer::allocateMemoryAndSetSize(int n){ size = n; array = new int[size]; }
void MatrixRep::convertDataToMatrixRep(int** array)
{
for(int i = 0 ; i != size; i++)
for(int j = 0; j != size; j++)
matrix[i][j] = array[i][j];
}
NodeContainer MatrixRep::returnNeighbours(int node)
{
deleteNeighboursIfAny();
if(!checkIfNotBeyondMatrix(node))
return neighbours;
neighbours.allocateMemoryAndSetSize(countNeighbours(node));
for(int i = 0, j = 0; i < size; i++)
if(matrix[node-1][i] != 0)
{
neighbours.array[j] = matrix[node-1][i];
j++;
}
return neighbours;
}
void MatrixRep::deleteNeighboursIfAny(){ if(neighbours.array) neighbours.~NodeContainer(); }
bool MatrixRep::checkIfNotBeyondMatrix(int node)
{
if(node == 0 || node > size)
{
std::cerr<<"There is no such a node!\n";
return false;
}
else
return true;
}
int MatrixRep::countNeighbours(int node)
{
int count_non_zero = 0;
for(int i = 0; i != size; i++)
if(matrix[node-1][i] != 0)
count_non_zero++;
return count_non_zero;
}
representation.h
struct NodeContainer
{
int size;
int* array;
NodeContainer();
~NodeContainer();
void allocateMemoryAndSetSize(int);
};
class MatrixRep
{
int size;
NodeContainer neighbours;
int** matrix;
public:
MatrixRep(int);
~MatrixRep();
void convertDataToMatrixRep(int**);
NodeContainer returnNeighbours(int);
void deleteNeighboursIfAny();
bool checkIfNotBeyondMatrix(int);
int countNeighbours(int);
void setupMatrix();
void deleteMatrix();
};
If you would like to return a copy of NodeContainer, you must implement a copy constructor and assignment operator for it. If you're using a C++11 conformant compiler it will also be good to also implement a move constructor and move assignment operator as well.
On the other hand, if you would like to not create a copy, you must either return a pointer or a reference to the member. You could also make the member a std::shared_ptr, which you may return in this case.
However, in your current implementation you're actually returning a shallow copy of NodeContainer. Once your copy goes out of scope its destructor is called, which deallocates its memory, which in this case is the original memory of your member, effectively making your member invalid. The implementation is not good as it is. So, depending on your goal, either implement the first advised solution, or the second.

Why does this code generate error?

I have a class that contains an array of another class called Sphere. Right now i am not sure why one part of code is generating an error.
.H file
sphere* list;
int listlen;
void add(sphere x);
sarray operator +(const sarray& arrayone);
.Cpp
sarray::sarray()
{
listlen = 0;
list = new sphere[200000];
}
sarray::~sarray()
{
delete [] this->list;
}
void sarray::add(sphere x) // Function for adding spheres to the list.
{
listlen++;
list[listlen-1] = x;
}
void sarray::operator = (const sarray& arrayone)
{
this -> list = NULL;
for(int i = 0; i < arrayone.listlen; i++)
{
this -> add(arrayone.list[i]);
}
}
sarray sarray::operator +(const sarray& arrayone)
{
sarray temparray;
for(int i = 0; i < arrayone.listlen; i++) // add all the elements from the first array to the temporary one
{
//sphere temp = arrayone.list[i];
temparray.add(arrayone.list[i]);
}
for(int j = 0; j < this -> listlen; j++)// add all the elements from the second array to the temporary one
{
temparray.add(list[j]);
}
return temparray;
}
The sphere class got a member variable called "Radius"
which when i try to compare like this
float a = 10;
for(int i=0; i > this->listlen;i++)
if(this->list[i].Radius > a) //<-- Can read the values
Works fine, but when change this part of the code
float a = 10;
sarray temparray = arrayone + *this;
for(int i = 0; i < temparray.listlen; i++)
if(temparray.list[i].radius > a) // Error comes here!
"Unhandled exception at 0x00138503: Access violation reading location"
while this doesent. I guess the problem is in the Add/operator function but i cant find it.
The following part looks problematic:
void sarray::add(sphere x) // Function for adding spheres to the list.
{
list[listlen-1] = x;
}
you should rather have something like this
void sarray::add(sphere x) // Function for adding spheres to the list.
{
list[listlen++] = x;
}
Also you should better have some error checking in add method.
OK, having looked at the destructor, you have a pointer to sphere in your sarray and has a destructor to destroy the pointer. This is all good except you haven't defined your own copy constructor which means the default copy constructor is used. In the function operator+ where you return temparray, a copy of the local copy is returned. The default copy constructor is called to create the copy. Then the local one will be destructed. Now the returned sarray copy's list will point to invalid data. You need to define your own copy constructor to make a deep copy of the list pointer.

A bunch of unclear things with the destructor in C++

I've written some very simple code in C++ to do some simple manipulations of vectors. This is the content of the file vector.h:
#ifndef VECTOR_H_INCLUDED
#define VECTOR_H_INCLUDED
class Vector {
int *coordinates;
int *size;
public:
Vector(int vector_size);
Vector(int*,int);
~Vector();
void print(void);
Vector operator +(Vector);
};
#endif
and this is the implementation (file: vector.cpp):
#include "vector.h"
#include <iostream>
using namespace std;
Vector::Vector(int vector_size) {
coordinates = new int[vector_size];
size = new int;
*size = vector_size;
}
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = new int;
*size = vector_size;
}
void Vector::print(void){
cout << "[";
for (unsigned short int index =0; index<*size; index++){
cout << coordinates[index];
if (index < *size-1){cout << ", ";};
}
cout << "]\n";
}
Vector Vector::operator+ (Vector other) {
Vector temp(*(other.size));
if ((*temp.size)!=(*(this->size))){
throw 100;
}
int* temp_c = new int[*(other.size)];
int* other_c = other.coordinates;
for (unsigned short int index =0; index<*size; index++){
temp_c[index] = coordinates[index] + other_c[index];
}
temp.coordinates = temp_c;
return (temp);
}
Vector::~Vector(){
delete[] coordinates;
delete size;
}
From my main.cpp, I do the following:
#include <iostream>
using namespace std;
#include "vector/vector.h"
const int size = 3;
int main() {
int *xxx = new int[size];
xxx[0]=4; xxx[1]=5; xxx[2]=-6;
Vector v(xxx,size);// v = [4, 5, -6]
Vector w(size);// w is a vector of size 3
w = v+v; // w should be w=[8,10,-12]
w.print();
return 0;
}
The result is then:
[148836464, 5, -6, 17, 148836384, 0, 0, 17, 0, 0, 0, 17, 3, 0, 0, 17, 0, 0, 0, 17, 148836480, 0, 0, 17, 0, 10, -12, 135025, 0, 0, 0, 0, 0, 0, , 0, 0,Segmentation fault
If I remove the two lines from the destructor:
delete[] coordinates;
delete size;
everything works as expected and the program outputs:
[8, 10, -12]
I would appreciate any explanations...
Update 1: I changed my operator+ method to the following, but the problem was not resolved:
Vector Vector::operator+(Vector other) {
int size_of_other = *(other.size);
int size_of_me = *(this->size);
if (size_of_other != size_of_me) {
throw 100;
}
int* temp_c = new int[size_of_me];
int* other_c = other.coordinates;
for (unsigned short int index = 0; index < size_of_me; index++) {
temp_c[index] = coordinates[index] + other_c[index];
}
Vector temp(temp_c,size_of_me);
return (temp);
}
Update 2: I noticed that using the operator:
Vector Vector::operator+(Vector other);
I wouldn't get the desired result. The modification that made it work was:
const Vector& Vector::operator+(const Vector& other) {
Vector temp(other.size);
for (unsigned short int index = 0; index < size; index++) {
cout << "("<< index <<") "<<coordinates[index] << "+"
<<other.coordinates[index] << ", "<< endl;
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return (temp);
}
Update 3: After update #2, I was getting a warning from the compiler that I return the local 'temp'. I changed my code to the following which completely resolved all problems and works fine (I return a copy of temp):
const Vector Vector::operator+(const Vector& other) const{
Vector temp(other.size);
for (unsigned short int index = 0; index < size; index++) {
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return *(new Vector(temp));
}
Your Vector::operator+ has at least one bug:
int* temp_c = new int;
...
temp_c[index] =
You are indexing temp_c when it was allocated with only a single integer. So your loop is stomping on some other memory, causing undefined behaviour.
You will also need to define a copy constructor so that you can properly use your Vector objects. The compiler generates a default copy constructor, but the default one is generally not suitable for objects that contain pointers.
This line:
temp.coordinates = temp_c;
causes a memory leak, because it overwrites the previously allocated temp.coordinates vector.
Update 3: Your code
return *(new Vector(temp));
while it appears to work, is still a memory leak. You are allocating a new Vector, then the compiler calls the copy constructor to copy that into the return value of your function. Nobody ever deletes the Vector object you just created, so there is a memory leak.
The solution is to write a copy constructor, instead of relying on the compiler-generated default copy constructor. All the other answers to your question have said the same thing. It is required that you do this for a correct program.
Your class needs a copy constructor and copy assignment operator to work correctly. A big hint that they are needed is that the destructor is not {}. See the "Rule of Three".
To get a bit better and more modern, you could also consider a move constructor and move assignment operator.
Try the code below which:
Implements a default constructor. This garauntees that however your object is constructed, your internal variables are going to be pointing at something on the heap or at NULL so any delete [] calls aren't going to die horribly.
Implements a copy constructor. Default copy constructors don't copy memory on the heap so that was going to be a serious problem for you.
Implements an assignment operator. Again this avoids shallow copies.
Removes size as a pointer; On most systems, pointers are the same size as integers so making size a pointer just makes things unnecessarily complicated.
Fixes the addition constructor by avoiding intermediate allocations. You had a temporary local variable there so make use of it instead of allocating several extra intermediate objects.
...take a look:
// VectorImplementation.cpp : Defines the entry point for the console application.
//
#include <iostream>
using namespace std;
class Vector {
int *coordinates;
int size;
public:
Vector();
Vector(int vector_size);
Vector(int*,int);
Vector(const Vector& v);
~Vector();
Vector operator +(Vector);
Vector& operator =(const Vector & other);
void print(void);
};
Vector::Vector() {
coordinates = NULL;
size = NULL;
}
Vector::Vector(int vector_size) {
coordinates = new int[vector_size];
size = vector_size;
}
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = vector_size;
}
Vector::Vector(const Vector& v) {
size = v.size;
coordinates = new int[size];
memcpy(coordinates,v.coordinates, sizeof(int)*size);
}
void Vector::print(void){
cout << "[";
for (unsigned short int index =0; index<size; index++){
cout << coordinates[index];
if (index < size-1){cout << ", ";};
}
cout << "]\n";
}
Vector Vector::operator+ (Vector other) {
Vector temp(other.size);
for (unsigned short int index =0; index<size; index++){
temp.coordinates[index] = coordinates[index] + other.coordinates[index];
}
return (temp);
}
Vector & Vector::operator= (const Vector & other)
{
if (this != &other) // protect against invalid self-assignment
{
// 1: allocate new memory and copy the elements
int * tmp_coordinates = new int[other.size];
memcpy(tmp_coordinates, other.coordinates, sizeof(int)*other.size);
// 2: deallocate old memory
delete [] coordinates;
// 3: assign the new memory to the object
coordinates = tmp_coordinates;
size = other.size;
}
// by convention, always return *this
return *this;
}
Vector::~Vector(){
printf("Destructing %p\n", this);
delete[] coordinates;
}
const int size = 3;
int _tmain(int argc, _TCHAR* argv[])
{
int *xxx = new int[size];
xxx[0]=4;
xxx[1]=5;
xxx[2]=-6;
Vector v(xxx,size);// v = [4, 5, -6]
Vector w(size);// w is a vector of size 3
w = v+v; // w should be w=[8,10,-12]
w.print();
return 0;
}
Doing that is a bad idea:
Vector::Vector(int* vector_coordinates, int vector_size){
coordinates = vector_coordinates;
size = new int;
*size = vector_size;
}
you assign coordinates pointer to data that you did not allocate, and then try to delete it in the destructor.
But the real reason that you get segfault is that you use the default copy constructor, and the temporary copy of v deletes the vector when it dies. You have to implement copy constructor and ensure deep copy or reference counting.
Try something like this:
Vector::Vector(const Vector& other){
size = new int(*other.size);
coordinates = new int[size];
memcpy(coordinates, other.coordinates, sizeof(int)*(*size));
}
Also, your operator+ would be much more efficient if you take const reference as an argument:
Vector Vector::operator+ (const Vector& other)
Consider the line
w = v+v; // w should be w=[8,10,-12]
a temporary object is constructed for the result of v+v, then assigned to w and destroyed.
Since you don't have and assignment operator a shallow copy is performed by the default implementation and you are working with deallocated memory.
The simple way to fix this issue is to implement a copy constructor/ assignment operator and destructor when you are allocating memory for members.