Why does this code result in the second element of the array being printed as 0, irrespective of the value that was specified in the definition of the integer array object?
The output of the code below is 7 0 3 4 5 6 instead of 7 2 3 4 5 6, what would be the reason for this behavior?
// Overloading operators for Array class
#include<iostream>
#include<cstdlib>
using namespace std;
// A class to represent an integer array
class Array
{
private:
int *ptr;
int size;
public:
Array(int *, int);
// Overloading [] operator to access elements in array style
int &operator[] (int);
// Utility function to print contents
void print() const;
};
// Implementation of [] operator. This function must return a
// reference as array element can be put on left side
int &Array::operator[](int index)
{
if (index >= size)
{
cout << "Array index out of bound, exiting";
exit(0);
}
return ptr[index];
}
// constructor for array class
Array::Array(int *p = NULL, int s = 0)
{
size = s;
ptr = NULL;
if (s != 0)
{
ptr = new int[s];
for (int i = 0; i < s; i++)
ptr[i] = p[i];
delete ptr;
}
}
void Array::print() const
{
for(int i = 0; i < size; i++)
cout<<ptr[i]<<" ";
cout<<endl;
}
// Driver program to test above methods
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
Array arr1(a, 6);
arr1[0] = 7;
arr1.print();
arr1[8] = 6;
return 0;
}
In the Array constructor, immediately after allocating and filling the dynamically allocated buffer at ptr, the buffer is released with
delete ptr;
All accesses of the buffer at ptr after this point invoke undefined behaviour. Side note: This should have been delete[] ptr; to ensure that the array was released correctly.
The solution: Don't do that!
Add a destructor to free ptr when Array goes out of scope and is done with the buffer.
// destructor for array class
Array::~Array()
{
delete[] ptr;
}
The compiler will automatically generate a destructor for you, but that generic destructor is not qualified to know whether or not it is safe to delete[] what's at a pointer member. It might not be an array, the allocation could be owned by another object (See What is ownership of resources or pointers?) or perhaps not allocated dynamically with new.
This brings up a side note: The default special member functions that handle copying this object will mindlessly copy the pointer, not the allocation, and leave you with two objects pointing to the same allocation. Sooner or later this will be fatal because one copy will go out of scope before the other and if nothing else tries to access the freed allocation and break the program, the second delete[] will break the program. This issue and its solution is covered in detail at What is The Rule of Three?
The general rule of thumb is to not make a class like this and instead use std::vector. std::vector does all of this and a whole lot more.
I modified the code as such to include an explicit default constructor and copy constructor, also included the std::out_of_range exception but am not sure if the latter is properly implemented.
This was done as an exercise in handling arrays without utilizing the vector container from STL.
Added a swap member function and assignment operator but getting a few error msgs.
class "Array" has no member "swap"
member "Array::size" (declared at line 12) is inaccessible
'operator=' must be a member function
'this' may only be used inside a nonstatic member function
// Overloading operators for Array class
#include<iostream>
#include<cstdlib>
//#include<vector>
using namespace std;
// A class to represent an integer array
class Array{
private:
int *ptr;
int size;
public:
Array(int *, int);
Array(const Array&);
~Array();
Array& operator= (Array);
// Overloading [] operator to access elements in array style
int &operator[] (int);
// Utility function to print contents
void print() const;
friend void swap(Array& first, Array& second);};
// Implementation of [] operator. This function must return a
// reference as array element can be put on left side
int &Array::operator[](int index){
// try {
// return ptr[index];}
// catch(const out_of_range& oor){
// cerr << "Out of Range error: " << oor.what() << '\n';}
if (index >= size || index < 0){
throw out_of_range("Index out of Range error");
}
return ptr[index];
}
// constructor for array class
Array::Array(int *p = NULL, int s = 0){
size = s;
ptr = NULL;
if (s != 0){
ptr = new int[s];
for (int i = 0; i < s; i++)
ptr[i] = p[i];}
}
// destructor for array class
Array::~Array(){
delete[] ptr;
ptr = NULL;}
// copy constructor for array class
Array::Array(const Array& A) {
size = A.size;
ptr = new int[size];
for (int i = 0; i < size; i++)
ptr[i] = A.ptr[i];}
void Array::swap(Array& first, Array& second){
using std::swap;
swap(first.size, second.size);
swap(first.ptr, second.ptr);}
//Assignment operator for array class
Array::Array& operator=(Array other){
swap(*this, other);
return *this;}
//print function for array elements
void Array::print() const{
cout << "{";
for(int i = 0; i < size; i++)
cout<<ptr[i]<<" ";
cout<<"}"<<endl;}
// Driver program to test above methods
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
Array arr1(a, 6);
arr1[0] = 7;
arr1.print();
Array arr2 = arr1;
arr2.print();
arr1[-1] = 4;
return 0;
}
Modified print function to exclude space after last array element.
Modified constructor method declaration to include initialized arguments.
Added additional const version of index[ ] operator overload but don't think it's properly implemented or if it would actually be utilized.
#include<iostream>
#include<cstdlib>
// A class to represent an integer array
class Array{
private:
int *ptr;
std::size_t size;
public:
Array(int *p = nullptr, std::size_t s = 0);
Array(const Array&);
~Array();
Array& operator= (Array);
// Overloading [] operator to access elements in array style
int &operator[] (std::size_t);
int const& operator[](std::size_t) const;
// Utility function to print contents
void print() const;
friend void swap(Array& first, Array& second);};
// Implementation of [] operator. This function must return a
// reference as array element can be put on left side
int &Array::operator[](std::size_t index){
puts("overload");
if (index >= size || index < 0){
throw std::out_of_range("Index out of Range error");
}
return ptr[index];
}
int const& Array::operator[](std::size_t index) const{
puts("const overload");
if (index >= size || index < 0){
throw std::out_of_range("Index out of Range error");
}
return ptr[index];
}
// constructor for array class
Array::Array(int *p, std::size_t s){
size = s;
ptr = nullptr;
if (s != 0){
ptr = new int[s];
for (int i = 0; i < s; i++){
ptr[i] = p[i];}
}
}
// destructor for array class
Array::~Array(){
delete[] ptr;
ptr = nullptr;}
// copy constructor for array class
Array::Array(const Array& A) {
size = A.size;
ptr = new int[size];
for (int i = 0; i < size; i++){
ptr[i] = A.ptr[i];}
}
//swap friend function of assignment operator
void swap(Array& first, Array& second){
using std::swap;
swap(first.size, second.size);
swap(first.ptr, second.ptr);}
//Assignment operator for array class
Array& Array::operator=(Array other){
swap(*this, other);
return *this;}
//print function for array elements
void Array::print() const{
std::cout << "{";
for(int i = 0; i < size; i++){
std::cout << ptr[i];
if (i == size-1){
continue;}
std::cout<<" ";
}
std::cout<<"}"<< std::endl;}
// Driver program to test above methods
int main()
{
int a[] = {1, 2, 3, 4, 5, 6};
Array arr1(a, 6);
std::cout << arr1[3] << '\n';
arr1[4] = 7;
arr1.print();
Array arr2 = arr1;
arr2.print();
arr1[-1] = 4;
return 0;
}
Related
CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
CheckedArray::~CheckedArray() {
if (mArray == NULL){
return;
}
else {
delete[] mArray;
}
}
I'm using dynamic memory allocation to create a new array. I want to check if the pointer is null, then return. If not, then delete. I'm getting these error messages, but I have no idea what's wrong.
(9094,0x100094600) malloc: *** error for object 0x10001e7b3: pointer being freed was not allocated
(9094,0x100094600) malloc: *** set a breakpoint in malloc_error_break to debug
To be completely clear
CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
should be
CheckedArray::CheckedArray(int size) :mSize(size), mArray(new int[size]){
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
Your version creates a local variable mArray which shadows the class variable of the same name.
Here is an example of what std::unique_ptr can do for you :
#include <iostream>
#include <algorithm>
#include <memory>
// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly
// so use https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
// prefer range based for loops, they can't go out of bounds : https://en.cppreference.com/w/cpp/language/range-for
class dynamic_int_array_t final
{
public:
// creates an "empty array" with enough memory for 4 ints.
dynamic_int_array_t() :
m_capacity{ 4ul }, // start with a capacity for 4 ints.
m_size{ 0ul }, // but actually none are stored yet
m_values{ std::make_unique<int[]>(m_capacity) }
{
}
// allows you to construct an array from a list of integers
dynamic_int_array_t(std::initializer_list<int>&& values) :
m_capacity{ values.size() },
m_size{ values.size() },
m_values{ std::make_unique<int[]>(m_capacity) }
{
std::copy(values.begin(), values.end(), m_values.get());
}
~dynamic_int_array_t() = default; // destructor will destruct unique_ptr and free memory
// non-copyable non-movable (simplifies things for now)
dynamic_int_array_t(const dynamic_int_array_t&) = delete;
dynamic_int_array_t& operator=(const dynamic_int_array_t&) = delete;
dynamic_int_array_t(dynamic_int_array_t&&) = delete;
dynamic_int_array_t& operator=(dynamic_int_array_t&&) = delete;
// begin and end allow range based for loops to work
// range based for loops don't allow you to go out of bounds.
auto begin() const
{
return m_values.get();
}
// end should point "one past" the array (that's how end works)
auto end() const
{
int* ptr = begin();
ptr += m_size;
return ptr;
}
std::size_t size() const
{
return m_size;
}
void add(const int value)
{
// if not enough memory then allocate more
if (m_size == m_capacity) grow_capacity();
// add new value at the end
m_values[m_size] = value;
m_size++;
}
// add another array to this one
void append(const dynamic_int_array_t& rhs)
{
for (int value : rhs)
{
add(value);
}
}
private:
void grow_capacity()
{
m_capacity *= 2;
// allocate new memory
auto tmp = std::make_unique<int[]>(m_capacity);
// copy content to new memory
std::copy(begin(), end(), tmp.get());
// swap new memory with tmp so m_values will now be the newly allocated memory and tmp will hold the previously allocated memory
std::swap(tmp, m_values);
// tmp will go out of scope and delete old buffer
}
std::size_t m_capacity;
std::size_t m_size;
std::unique_ptr<int[]> m_values;
};
int main()
{
dynamic_int_array_t array{ 4,5 };
for (int n = 10; n < 20; ++n)
{
array.add(n);
}
for (const int value : array)
{
std::cout << value << " ";
}
return 0;
}
For my first try with operator overloading I created a vector class and tried to sum up two vectors. My class contains an array and a vector of int that both contain the same elements.
Addition works fine with the std::vector but I encounter two issues with the array. It seems that the destructor is called at the end of the summing operation which produces a "double free or corruption" error (core dump). Plus, the first two elements of the array are always equal to zero.
Should I also overload the delete or am I missing a thing ?
The header file:
#ifndef MYVECTOR_INCLUDE
#define MYVECTOR_INCLUDE
#include <iostream>
#include <stdexcept>
#include <cstring>
#include <vector>
class MyVector {
public:
MyVector(int n);
~MyVector();
void set(int idx, int value);
int get(int idx);
void print();
MyVector &operator=(const MyVector &v);
MyVector operator+(const MyVector &v);
private:
int *data;
std::vector<int> data_vector;
int size1;
int size2;
};
#endif
The cpp file:
#include "../include/myvector.hpp"
MyVector::MyVector(int n) {
data = new int [n];
data_vector.resize(n);
size1 = n;
size2 = 1;
}
MyVector::~MyVector() {
if (data != NULL) {
delete [] data;
}
}
void MyVector::set(int idx, int value) {
data_vector[idx] = value;
data[idx] = value;
}
int MyVector::get(int idx) {
return data_vector[idx];
}
void MyVector::print() {
std::cout << "Vector data" << std::endl;
for (int i = 0; i < size1; ++i) {
std::cout << data_vector[i] << " ";
}
std::cout << std::endl;
std::cout << "Data" << std::endl;
for (int i = 0; i < size1; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
MyVector &MyVector::operator=(const MyVector &v) {
if (this == &v)
return *this;
size1 = v.size1;
size2 = v.size2;
std::copy(v.data_vector.begin(), v.data_vector.end(), data_vector.begin());
memcpy(&data, v.data, sizeof(int)*size1);
return *this;
}
MyVector MyVector::operator+(const MyVector &v) {
if ((size1 == v.size1) && (size2 == v.size2)) {
MyVector res = MyVector(size1);
for (int i = 0; i < size1; ++i) {
res.data_vector[i] = data_vector[i] + v.data_vector[i];
res.data[i] = data[i] + v.data[i];
}
return res;
}
else
throw std::length_error("Vector dimensions must agree.");
}
Thank you.
See the rule of three/five/zero.
The rule of three states
If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three.
In this case, you provided the destructor and copy assignment operator but forgot the copy constructor.
In operator+ you create a local object MyVector res which is later copied out and then destroyed. Since you haven't implemented a copy constructor, the default copy constructor will simply copy the original data pointer from res to another MyVector. When res is destroyed, the array pointed to by it's data member will be deleted, leaving the copied vector's data pointing to a deleted object.
I am in my first C++ this semester and am having some issues with a MyVector class I created earlier on in the class. I made variables global for the object which is a "NO NO" as my teacher said for object oriented programming. I believed I have declared the variables correctly now, but ever since I am receiving an
"Invalid allocation size: 4294967295 bytes." When calling my push_back
function.
Below is my code (MyVector.h, and MyVector.cpp), I understand that using using namespace std; is not best practice but this is how my teacher wants it.... I don't know why.
I have stepped through my code and can't identify what I need to do next. I have a feeling it is how I had the variable declared before. They were previously in the MyVector.cpp declared globally as follows before the change.
//Declarations
int vSize;
int* myArray;
int startCap = 2;
const int TWO = 2;
const int ZERO = 0;
Any help or a point in the right direction would be appreciated.
Thanks in advance!
The Call from the driver.cpp
cout << "\nCreating a vector Sam of size 4.";
MyVector sam( 4 );
cout << "\nPush 12 values into the vector.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
MyVector.h
class MyVector
{
public:
int vSize;
int* myArray;
int startCap;
//Constructor
MyVector ();
MyVector (int n);
//Deconstructor
~MyVector ();
//Copy Constructor
MyVector(const MyVector&);
//Overloaded Assignment Operator
MyVector& operator=(const MyVector&);
//Getter Function: size
//Purpose: Return the size of the vector
//Return Type: int
//Parameters: NONE
int size () const;
//Getter Funcation: capacity
//Purpose: Return the capacity of the vector
//Return Type: int
//Parameters: NONE
int capacity () const;
//Setter Funcation: clear
//Purpose: Clears the contents of the vector and sets the siz to zero and the capacity to two
//Return Type: void
//Parameters: NONE
void clear ();
//Setter Funcation: push_back
//Purpose: Adds integer to vector. If vector is not big enough double the vectors current capacity
//Return Type: void
//Parameters: int n
void push_back (int n);
//Getter Function: at
//Purpose: Return value of emement at position n
//Return Type: Int
//Parameters: int n
int at (int n) const;
// overloaded << operator - a nonmember
// make it a friend so it can see the array
friend ostream& operator<<(ostream& out, const MyVector& s);
};
MyVector.cpp
//default constructors
MyVector::MyVector()
{
int startCap = 2;
int vSize = 0;
myArray = new int[startCap];
}
MyVector::MyVector(int n)
{
int startCap = n;
int vSize = 0;
myArray = new int[startCap];
}
//Deconstructor
MyVector::~MyVector()
{
//deleting myArray and clearing it
if (myArray != NULL)
{
delete [] myArray;
myArray = NULL;
}
}
// Copy constructor
// Purpose: Copy the data into this Array
// Parameters: a MyVector object
// Returns: none
MyVector::MyVector( const MyVector& v)
{
// Be sure that the string is not null
if ( v.myArray != NULL )
{
// allocate storage and copy char array
startCap = v.startCap;
//theStr = new char[strlen(b.theStr) + 1];
myArray = new int[startCap];
//strncpy(theStr, b.theStr, theStrLen );
for (int i = 0; i < startCap; i++)
myArray[i] = v.myArray[i];
}
else // nothing to copy
{
myArray = NULL;
startCap = 0;
}
}
// The overloaded assignment operator
MyVector& MyVector::operator= (const MyVector& v)
{
// test for self-copy
if (this == &v)
return *this;
// Consider two cases.
if (startCap >= v.startCap) // there is room
{
if (v.myArray != NULL)
{
for (int i = 0; i < startCap; i++)
{
this->myArray[i] = v.myArray[i];
}
}
else // copying a null string
myArray = NULL;
startCap = v.startCap;
return *this;
}
else // not enough room
{
// delete the original array
delete [] myArray;
startCap = v.startCap;
if (startCap > 0) // okay, something to copy
{
// allocate the storage and copy
myArray = new int[startCap + 1];
for (int i = 0; i < vSize; i++)
{
this->myArray[i] = v.myArray[i];
}
}
else // nothing to copy
myArray = NULL;
return *this;
}
}
//Getter Function: size
//Purpose: Return the size of the vector
//Return Type: int
//Parameters: NONE
int MyVector::size() const
{
return vSize;
}
//Getter Funcation: capacity
//Purpose: Return the capacity of the vector
//Return Type: int
//Parameters: NONE
int MyVector::capacity() const
{
return startCap;
}
//Setter Funcation: clear
//Purpose: Clears the contents of the vector and sets the siz to zero and the capacity to two
//Return Type: void
//Parameters: NONE
void MyVector::clear()
{
//clearing the array and setting the array to the default cap of 2 and size of 0
if (myArray != NULL)
{
delete [] myArray;
myArray = NULL;
}
vSize = 0;
startCap = 2;
int* myArray = new int[startCap];
}
//Setter Funcation: push_back
//Purpose: Adds integer to vector. If vector is not big enough double the vectors current capacity
//Return Type: void
//Parameters: int n
void MyVector::push_back(int n)
{
//verifying the we are not writting the value
//past the capacity of the array
if(vSize + 1 > startCap)
{
//Doubling the array size
startCap = vSize * 2;
//creating a temp array
int* temp = new int[startCap];
//for loop copying the contents of myArray to temp
for (int i = 0; i < vSize; i++)
{
temp[i] = myArray [i];
}
//deleting the myArray
delete[] myArray;
//copying myArray from temp
myArray = temp;
}
//finding the end of the array and incrementing and adding one to the array
myArray[vSize] = n;
vSize++;
}
//Getter Function: at
//Purpose: Return value of emement at position n
//Return Type: Int
//Parameters: int n
int MyVector::at(int n) const
{
//If statment that returns value of the point in the array
//or throws an error telling the user the index at which it failed
if(n < vSize)
return myArray[n];
throw n;
}
ostream& operator<<(ostream& out, const MyVector& s)
{
for (int i = 0; i < s.vSize; i++)
out << s.myArray[i] << ' ';
return out;
}
you are creating a same variable within the constructor and clear, which has the same name is the one in the class, initialize it.
and by the time you leave the constructor or clear, the main variables, don't get any changes.
its an initializing issue, especially the ones in the constructor
in clear function
int* myArray = new int[startCap];
should be
myArray = new int[startCap];
also inside the constructor
int startCap = n;
int vSize = 0;
should be
startCap = n;
vSize = 0;
When you want to assign to an instance variable, don't put the type on the name. That'll create a local variable with the same name as the instance variable instead of assigning to the actual instance variable, causing your instance variables to have incorrect, possibly even uninitialized values. This problem shows up in your first two constructors and your clear method.
I'm getting an error when trying to cout the return value of Data[index]. If anyone could help me that would be awesome. I know usually these errors are caused by allocated conflicting memory or having a pointer reference a deleted index, etc. Although I don't delete anything so I don't know where this error is coming from.
Header file:
#pragma once
#define INITIAL_CAPACITY 100
#define CAPACITY_BOOST 40
//Encapsulates the C-array
template <typename DATA_TYPE>
class Vector
{
public:
//Default / init-constructor hybrid
Vector(int initialCapacity = INITIAL_CAPACITY)
{
Size=0;
Capacity = initialCapacity;
//Allocate the encapsulated C-array
Data= new DATA_TYPE[Size];
}
//MUST HAVE A COPY-CONSTRUCTOR THAT PERFORMS deep-copy
Vector(const Vector& copyFrom)
{
//Necessary to prevent assignment operator from crashing
//because it will attempt to Delete[] Data whe the Data pointer is garbage.
Data=NULL;
//Use assignment operator to perform the deep copy
*this = copyFrom;
}
//The class MUST have a destructor
~Vector()
{
//Deallocate memory that our class has allocated
delete[] Data;
}
//MUST have an assignment operator that performs deep copy
Vector& operator =(const Vector& copyFrom)
{
//0. Delete the old memory
delete[] Data;
//1. Copy size and Capacity
Size = copyFrom.Size;
Capacity = copyFrom.Capacity;
//2. Allocate Memory
Data = new DATA_TYPE[Capacity];
//3. Copy elemenets
for(int i=0; i < Size; i++)
Data[i]= copyFrom.Data[i];
//All assignment operators should return *this
return *this;
}
//Get accessors to return the values of Size and Capacity
int GetSize() const
{
return this->Size;
}
int GetCapacity() const
{
return Capacity;
}
void Insert(int insertAt, const DATA_TYPE& newElement)
{
//**ASSIGNMENT**
//1. Determine if we have enough capacity for extra element(reallocate)
Size=GetSize();
if(Size>=Capacity)
{
Capacity += CAPACITY_BOOST;
}
//Use a function to check bounds.
if((insertAt > Capacity)||(insertAt < 0))
{
throw "Index is out of bounds";
}
//2.Move the tail
for (int i=Size+1; i > insertAt; i--)
Data[i]=Data[i-1];
//3.Insert element
Data[insertAt]= newElement;
}
//Inserts a new element at the end fo the Vector and increments the size
void Add(const DATA_TYPE& newElement)
{
Insert(Size, newElement);
Size++;
}
void Remove(int index)
{
delete Data[index];
for(i=index; i < Size-1; i++)
Data[i]=Data[i+1];
Size--;
Capacity=Size;
//**ASSIGNMENT**
//Resize. Shrink vector when you have too much capacity
//TEST EVERYTHING
}
// Index operator
DATA_TYPE operator[] (int index) const
{
// Check the bounds and throw an exception
if ( (index < 0) || (index >= Size) )
throw "Error";
return Data[index];
}
private:
//The count of actually used C-array elements
int Size;
//The count of the allocated C-array elements
int Capacity;
//The encapsulated C-array (pointer)
DATA_TYPE* Data;
};
Main:
#include <iostream>
#include "vector.h"
using namespace std;
#define TEST_CAPACITY 100
#define TEST_SIZE 10
template<typename DATA_TYPE>
void PassByValueTest(Vector<DATA_TYPE>passedByValue)
{
}
void main()
{
//myVector is initialized using the default constructor
Vector<int> myVector;
//Populate myVector with some test values
for (int i=0; i< TEST_SIZE; i++)
myVector.Add(i);
//myOtherVector initialized using the init-constructor, initial capacity is 10
//Vector<int> myOtherVector(TEST_CAPACITY);
//Test by passing vector by value
/*
PassByValueTest(myVector);
myVector = myOtherVector;
*/
for(int i = 0; i < TEST_SIZE; i++)
{
cout << myVector[i];
}
system("pause");
}
I guess you should switch:
Data= new DATA_TYPE[Size];
to
Data= new DATA_TYPE[Capacity];
you are doing Data = new DATA_TYPE[0];
Vector(int initialCapacity = INITIAL_CAPACITY)
{
Size=0; // <<<---
Capacity = initialCapacity;
//Allocate the encapsulated C-array
Data= new DATA_TYPE[Size]; // note Size is 0
}
Then access to Data[i] is undefined behavior:
for(int i = 0; i < TEST_SIZE; i++)
{
cout << myVector[i];
}
Side note, you should return int from main, there is no void main in standard:
int main()
{
}
How do you copy an object of a class to another object of the same class just by using '='. I know that we have to overload the operator. here's what I have so far
#include<iostream>
#include<conio.h>
#include<iomanip>
using namespace std;
class arr
{
public:
int *arr1;
int len;
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
friend istream& operator >> (istream& ist, arr & r)
{
static int i = 0;
int *arrNew;
if (i == r.len)
{
r.len *=2;
arrNew = new int[r.len]; // allocate the new array
for(int j = 0; j < r.len/2; j++)// copy the old array to the first half of the new array
arrNew[j] = r.arr1[j];// delete the old array
delete [] r.arr1;// let arr point to the new array and continue use arr
r.arr1 = arrNew;
delete arrNew;
}
ist>>r.arr1[i];
i++;
return ist;
}
arr() //initializing constructor
{
len = 5;
arr1 = new int[len];
};
arr(int size) //initializing constructor with args
{
len = size;
arr1 = new int[len];
};
arr(arr& a) : arr1(a.arr1) //copy constructor
{
arr1 = new int[len];
};
~arr() //delete constructor
{
delete arr1;
};
};
void main()
{
int size = 5,i,temp,trig = 0;
arr orig(size), asc(size), desc(size);
//generate random numbers for orig
for (i = 0 ; i < size ; i++)
{
orig.arr1[i] = rand();
}
//copy original set to asc and desc
asc = orig;
desc = orig;
//sorting ascending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (asc.arr1[i] < asc.arr1[i+1])
{
temp = asc.arr1[i];
asc.arr1[i] = asc.arr1[i+1];
asc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//sorting descending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (desc.arr1[i] > desc.arr1[i+1])
{
temp = desc.arr1[i];
desc.arr1[i] = desc.arr1[i+1];
desc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//printing
cout<<"Original Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<orig.arr1[i]<<" ";
}
cout<<endl;
cout<<"Ascending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<asc.arr1[i]<<" ";
}
cout<<endl;
cout<<"Descending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<desc.arr1[i]<<" ";
}
cout<<endl;
getch();
}
It compiles properly but it ('asc' and 'desc') displays numbers that are different from the 'orig' object.
The proper solution is something like this:
struct Foo
{
std::vector<int> arr;
friend std::ifstream & operator>>(/*...*/);
};
The implicitly defined assignment operator already does exactly what you need, and clever code reuse is the heart of C++ programming ("a language for library design").
If you want to write it by hand, you have to make the copy yourself:
struct Bar
{
unsigned int len;
int * arr;
Bar & operator=(Bar const & rhs)
{
len = rhs.len;
delete[] arr;
arr = new int[len];
for (unsigned int i = 0; i != len; ++i) { arr[i] = rhs.arr[i]; }
return *this;
}
Bar() : len(), arr() { }
// more constructors
Bar(Bar const &); // exercise: write this!
~Bar() { delete[] arr; }
};
This is a terrible, terrible idea, though, since this pattern doesn't generalize at all: it isn't exception safe -- imagine one of the copies in the for-loop threw an exception. Now you've lost your original data and leaked memory.
A better solution would be to allocate a temporary buffer first:
int * temp = new int[len];
for (...) temp[i] = rhs.arr[i];
delete[] arr;
arr = temp;
Now this code is quickly getting very ugly, and imagine you had more than one of those!
In a nutshell: use std::vector.
You don't need a temporary array object in the assignment operator, and you should copy to the array in this, and then return *this:
arr &operator=(const arr &eq)
{
// If "this" already has an array, then delete it
if (arr1)
delete [] arr1;
// Create a new array of the same length as the one we're assigning from
len = eq.len;
arr1 = new int [len];
// And copy the array
memcpy(arr1, eq.arr1, len * sizeof(int));
// Returning "*this" allows the assignment operator to be chained
return *this;
}
what you have implemented in operator overloading is quite confusing and seems wrong to me
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
1.why are you creating a new object temp?
2.why create a pointer of type arr. and assigning pttemp to point to temp whose scope is with in the function and then you are not using
it anywhere!!
you need not create a new object inside the function as "this" pointer is implicitly passed to the function.
you should overload it this way
arr& operator = (const arr& source)
{
//this->len = source.len;
len = source.len;
for(int i=0;i < source.len ; i++)
{
//this->arr1[i] = source.arr1[i];
arr1[i] = source.arr1[i];
}
return *this;
}
Your copy constructor also looks wrong, it doesn't copy the contents of the array.
I agree with Kerrek that you should use vector. But since you appear to be trying to re-implement vector for yourself, here's a simple "correct" way to manage the resources in your class, for illustration:
class arr
{
public:
// switch order of data members, we want to initialize "len" first
int len;
int *arr1;
// default constructor
// you could use "new int[len]()" instead, to zero-initialize the array
arr() : len(5), arr1(new int[len]) {}
// constructor with size
arr(int size) : len(size), arr1(new int[len]) {}
// copy constructor
arr(const arr &rhs) : len(rhs.len), arr1(new int[len]) {
std::copy(rhs.arr1, rhs.arr1 + len, arr1);
}
// destructor
~arr() {
delete[] arr1; // *not* "delete", you *must* use "delete[]"
}
// swap function (this is useful, observe that it cannot throw)
void swap(arr &rhs) {
std::swap(len, rhs.len);
std::swap(arr1, rhs.arr1);
}
// assignment operator
arr &operator=(arr temp) { // parameter by value uses the copy ctor
// so, anything that could throw (the allocation) is complete,
// before we make any modifications to this object.
// see how useful "swap" is, and the fact it cannot throw?
swap(temp);
return *this;
}
// for C++11
// move constructor
arr(arr &&rhs) : len(rhs.len), arr1(rhs.arr1) {
rhs.arr1 = 0;
}
};
Btw, the name of the data member arr1 makes me fear that you're going to add a second array later. Do not do this, it's far more trouble to write a class that correctly manages two resources, than it is to write a class that correctly manages one resource and another class that has two of those as data members.