I am working on an assignment for my c++ class and am having trouble with one portion of the class that requires resizing a dynamic array. For this assignment, I need to store terms of a polynomial in a dynamic array. I am specifically having trouble with the setCoefficient function of my code, where I need to resize a dynamic array if I am trying to at a term to my polynomial that is larger than what the array can currently hold.
I tried following some other stack overflow posts on how to resize a dynamic array, but keep running into errors. Currently, I am running into an error of HEAP CORRUPTION DETECTED when I try and delete the old dynamic array in the setCoefficient function.
I have commented the setCoefficient function and was hoping someone could go through and help me determine where I am going wrong. Unfortunately, I am not allowed to use the STL vector class for this assignment.
Here is my .cpp file where you can see the implementation of the setCoefficient function that I am having trouble with:
#include "poly.h"
//Default constructor. Initializes a Poly to: 0x^0
Poly::Poly()
{
cout << "No parameter constructor called" << endl;
polyArray = new int[1];
//polyArray[1] = 0;
polyArray[0] = 0;
length = 0;
}
//Constructor with one argument. Initialized to: coefficientx^0
Poly::Poly(int coefficient)
{
cout << "One parameter constructor called" << endl;
cout << "coefficient: " << coefficient << endl;
polyArray = new int[1];
//polyArray[1] = 0;
polyArray[0] = coefficient;
length = 0;
}
//Constructor with two arguments. Initialized to: coefficientx^power
Poly::Poly(int coefficient, int power)
{
cout << "Two parameter constructor called" << endl;
cout << "power: " << power << endl;
cout << "coeff: " << coefficient << endl;
polyArray = new int[power]; //I think I need to add 1 here to account for that fact that arrays start at index 0.
for (int i = 0; i < power; i++) { //I want to initialize the dynamic array to all 0's
polyArray[i] = 0;
}
polyArray[power] = coefficient;
length = power;
}
//Destructor
Poly::~Poly()
{
cout << "I am the destructor" << endl;
polyArray = NULL;
delete [] polyArray;
}
//Copy constructor. Creates a deep copy of a Poly.
Poly::Poly(const Poly& p)
{
cout << "Copy constructor" << endl;
this->length = p.length;
cout << "this->length: " << this->length << endl;
cout << "p.length: " << p.length << endl;
this->polyArray = new int[this->length];
//Loop throguh the initial Poly and assign all values in the array to the new Poly.
for (int i = 0; i<=p.length; i++) {
this->polyArray[i] = p.polyArray[i];
cout << "this polyArray: " << this->polyArray[i] << endl;
cout << "p.polyArray: " << p.polyArray[i] << endl;
}
}
void Poly::setCoefficient(const int coefficient, const int power) {
if (power > this->length) {
//we need to resize the array we currently have.
//Here I am creating a new array that will temporarily store larger values
int* resizedArray = new int[power * 2];
//This for loop assigns all the values in the current object's array to the new array (resizedArray)
for (int i = 0; i < this->length; i++) {
resizedArray[i] = this->polyArray[i];
}
//Here I am adding the term that we wanted to add in the first place with setCoefficient
resizedArray[power] = coefficient;
//Deleting the terms in polyArray
delete [] this->polyArray;
//Creating a new array that has been resized
this->polyArray = new int[power * 2];
//Setting the values of the temporary array, resizedArray, to the array of the current object.
this->polyArray = resizedArray;
//modifying the length of the current object.
this->length = power * 2;
}
else {
this->polyArray[power] = coefficient;
}
}
and for completeness, here is my .h file as well (although I dont think the issue is in my .h:
// ------------------------------------------------ Poly.h ----------------------------------------------
#ifndef Poly_H
#define Poly_H
#include <iostream>
#include <string>
using namespace std;
class Poly {
friend ostream& operator<<(ostream& out, const Poly& p);
friend istream& operator>>(istream& in, Poly& p);
public:
//Member functions
Poly(); //Default constructor. Initializes a Poly to: 0x^0
Poly(int coefficient); //Constructor with one argument. Initialized to: coefficientx^0
Poly(int coefficient, int power); //Constructor with two arguments. Initialized to: coefficientx^power
Poly(const Poly& p); //Copy constructor. Creates a deep copy of a Poly.
~Poly(); //Destructor
int degree() const; //Returns the largest degree term in a Poly.
double getCoefficient(const int power) const; //returns the coefficient of the x^power term.
//Poly setCoefficient(const int coefficient, const int power); //Sets the coefficient of the term indicated by the power.
void setCoefficient(const int coefficient, const int power);
// Arithmetic operators
Poly operator+(const Poly& p) const;
Poly operator-(const Poly& p) const;
// Boolean comparison operators
bool operator==(const Poly& p) const;
bool operator!=(const Poly& p) const;
// Assignment operators
Poly& operator=(const Poly& p);
Poly& operator+=(const Poly& p);
Poly& operator-=(const Poly& p);
Poly& operator*=(const Poly& p);
//Clean up/delete all Poly terms.
void clear();
//Checks if the Poly is empty or not.
bool isEmpty() const;
private:
int length; //# of terms in the Poly/size of the array
int* polyArray;
};
#endif
One error is here (cout statements removed for brevity):
this->length = p.length;
this->polyArray = new int[this->length];
for (int i = 0; i<=p.length; i++) {
this->polyArray[i] = p.polyArray[i];
}
The test in your for-loop should be i<p.length rather than i<=p.length. Otherwise you are writing one value past the end of polyArray, which invokes undefined behavior (which can result and often does in a crash)
Related
So I'm trying to write a vector class which can take objects without a default constructor. To do so I'm using an array of raw pointers. Thing is, when I'm instantiating a new vector, let's call it 2, based upon a previous vector, let's call it 1-- it points to the underlying address of said previous object, 1. So when I insert a new value into 1, 2 is updated as well.
#ifndef MYVECTOR_MYVECTOR_H
#define MYVECTOR_MYVECTOR_H
#include <sstream>
#include <stdexcept>
#include <memory>
#include <vector>
#include <ostream>
template<typename T>
class MyVector;
template<typename T>
std::ostream& operator<<(std::ostream& out, const MyVector<T>& myVec){
out << "{";
for(int i = 0; i < myVec.numElem; i++){
out << &myVec.elements[i] << " ";
}
out << "}";
return out;
}
template<typename T>
class MyVector{
public:
int numElem;
int capacity;
T** elements;
MyVector(const unsigned int& numElements, const T& value) : numElem(numElements), capacity(numElements * 2){
elements = new T*[capacity];
for(int i = 0; i < numElem; i++){
elements[i] = new T(value);
}
}
template<typename U>
MyVector(const std::vector<U>& values): numElem(values.size()), capacity(values.size() * 2){
elements = new T*[capacity];
for(int i = 0; i < numElem; i++){
elements[i] = new T(values[i]);
}
}
void insert(const unsigned& pos, const T& value){
elements[numElem] = new T(*elements[numElem - 1]);
numElem++;
for(unsigned int i = numElem - 1; i > pos; i--){
elements[i] = elements[i - 1];
}
elements[pos] = new T(value);
}
};
#endif
Per comment #1:
class NoDefault {
public:
NoDefault(const int& value) : value(value) {}
int value;
};
std::ostream& operator<<(std::ostream& out, const NoDefault& noDefault) {
out << noDefault.value;
return out;
}
int main() {
MyVector<NoDefault> noDefaultVec(std::vector<NoDefault>{7,8,9,10,11});
MyVector<MyVector<NoDefault>> vecvec(2, noDefaultVec);
std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
std::cout << "vecvec = " << vecvec << std::endl;
noDefaultVec.insert(3, 99);
vecvec.insert(1, noDefaultVec);
std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
std::cout << "vecvec = " << vecvec << std::endl;
return 0;
}
You perform a shallow copy instead of a deep copy.
A shallow copy of your vector creates a new collection which shares elements with an old one. What follows, any change made to the original object will cause a change in a new one. What you need in that case is a deep copy, which duplicates every element from the source to the destination. After performing such a copy you are left with two vectors with seperate set of data.
Providing a copy constructor for your class solves the problem, but you should also remember about implementing destructor and assignment operator, basing on The Rule Of Three. You can also consider adding move constructor and move assignment operator (or one assignment operator following copy-and-swap idiom).
I ran this example:
#include <cstdlib>
#include <iostream>
#include <istream>
#include <ostream>
using namespace std;
class Weight {
int k;
char a[100];
public:
Weight(int kilos = 0)
:k(kilos) {}
Weight(const Weight& w)
: k(w.k) {
for(int i = 0; i < 100; ++i) this->a[i] = 'a';
cout << "WCC\n";
}
friend Weight operator+(const Weight& a, const Weight& b);
Weight& operator=(const Weight & w) {
this->k = w.k;
return *this;
}
friend ostream& operator<<(ostream&, const Weight&);
};
Weight operator+(const Weight& a, const Weight& b) {
cout << "FP\n";
int newkg = a.k + b.k;
return Weight(newkg);
}
ostream& operator<<(ostream& out, const Weight& w) {
out << w.k << " KGs";
return out;
}
class Container{
Weight w;
static Weight totalW;
static int count;
public:
Container(){++count;}
~Container(){cout << "CD\n";}
Container& add(Weight weight) {
this->w = this->w + weight;
totalW = totalW + weight;
cout << "Just added a new item that weighs " << weight << endl;
return *this;
}
static void print() {
cout << "We have " << count << " Containers with a total weight "
<< totalW << endl;
}
friend ostream& operator<<(ostream&, const Container&);
};
Weight Container::totalW;
int Container::count = 0;
ostream& operator<<(ostream& out, const Container& c){
out << "This container's " << c.w;
return out;
}
int main(int argc, char** argv) {
Container c1;
Weight *w1 = new Weight(1);
Weight *w2 = new Weight(2);
Weight *w3 = new Weight(3);
cout << "Adding items to container...\n";
c1.add(*w1).add(*w2).add(*w3);
cout << c1 << endl;
Container::print();
return 0;
}
And I got this output:
Adding items to container...
WCC
WCC
WCC
FP
FP
Just added a new item that weighs 1 KGs
FP
FP
Just added a new item that weighs 2 KGs
FP
FP
Just added a new item that weighs 3 KGs
This container's 6 KGs
We have 1 Containers with a total weight 6 KGs
CD
You can see that the copy constructor for the Weight class was called three times (Output lines 2-4) before any of the cascaded functions was called. I always thought that the left most function call will be performed before any copy constructor is called up to setup the second function call.
To be more specific, I thought this what should have happened:
WCC -> c1.add(*w1) -> WCC -> .add(*w2) -> WCC -> .add(*w3).
I thought this was necessary because the function argument will be stored in the function's stack frame. So, a stack frame needs to be setup before the copy constructor for the argument is called. Apparently, I am mistaken.
This makes me think that function arguments are store somewhere else other than the stack frame. So, where?
Do not mind the horrific coding style. This, obviously, is not meant to be in production code.
I think this is a basic compiler optimization. Since there's no requirement when a function's parameters should be initialized from supplied arguments, a compiler can do necessary optimization by rearranging them. That's why you see the copy constructors called all at once.
I've read many posts with the same error, unfortunately all of those deal with indexing off the end of an array. In my case I get the error when I assign the array to a variable in my constructor.
Here is my code:
Heap.cpp
#include "./Heap.h"
#include <iostream>
#include <sstream>
// Provides floor, ceil, etc.
#include <cmath>
using namespace std;
Heap::Heap() {
arraySize = 0;
n = 0;
A = NULL;
}
// This assumes that every element of the array is an
// element of the heap.
Heap::Heap(int* inArray, int inArraySize, int inHeapSize) {
// TODO: initialize your class data members. An array dynamically allocated
// as follows:
// A = new int[size];
// If you allocate an array like this you MUST deallocate it in your
// destructor. This is done for you in the destructor below.
arraySize = inArraySize;
n = inHeapSize;
A = new int[arraySize];
A = inArray;
}
// Destructor. Cleans up memory.
Heap::~Heap() {
delete [] A;
}
// Note: the function name is prefixed by Heap:: (the class
// name followed by two colons). Any function defined in
// the .cpp file must have this prefix.
int Heap::at(int i) const {
return A[i];
}
int Heap::parent(int i) const{
return (int) (i - 1) / 2;
}
int Heap::left(int i) const {
return (i + 1)* 2 - 1;
}
int Heap::right(int i) const {
return (i + 1) * 2;
}
bool Heap::hasLeft(int i) const {
int leftIndex = left(i);
std::cout << "left index = " << leftIndex<< std::endl;
return false;
}
bool Heap::hasRight(int i) const{
return false;
}
void Heap::maxHeapify(int i){
}
//
void Heap::buildMaxHeap(){
}
bool Heap::operator==(const Heap& rhs) {
if (n != rhs.n) return false;
for (int i = 0; i < n; ++i) {
if (A[i] != rhs.A[i]) return false;
}
return true;
}
bool Heap::operator==(const int* rhs) {
for (int i = 0; i < n; ++i) {
if (A[i] != rhs[i]) return false;
}
return true;
}
std::ostream& operator<<(std::ostream& out, const Heap& h) {
out << "[";
for (int i = 0; i < h.n; ++i) {
out << h.A[i];
if (i < h.n-1) {
out << ", ";
}
}
out << "]";
return out;
}
string toDotImpl(const Heap& h, int i) {
using namespace std;
stringstream ss;
if (h.hasLeft(i)) {
ss << toDotImpl(h, h.left(i));
ss << "\"" << h.at(i) << "\" -> \""
<< h.at(h.left(i)) << "\"\n";
}
if (h.hasRight(i)) {
ss << toDotImpl(h, h.right(i));
ss << "\"" << h.at(i) << "\" -> \""
<< h.at(h.right(i)) << "\"\n";
}
return ss.str();
}
string toDot(const Heap& h) {
using namespace std;
stringstream ss;
ss << "digraph G {\n";
ss << "graph [ordering=\"out\"]\n";
ss << "\"" << h.at(0) << "\"\n";
ss << toDotImpl(h, 0);
ss << "}\n";
return ss.str();
}
and
Heap.h
#pragma once
// Provides I/O
#include <iostream>
// Provides size_t
#include <cstdlib>
// Provides INT_MAX and INT_MIN
// You can consider INT_MIN to be negative infinity
// and INT_MAX to be infinity
#include <climits>
//------------------------------------------------------------
// Heap class
//------------------------------------------------------------
class Heap {
public:
// Constructor
Heap();
// This constructor assumes that every element of the array is an
// element of the heap.
Heap(int* inArray, int inArraySize, int inHeapSize);
// Destructor
~Heap();
// Accesses an element of the array.
int at(int i) const;
// Gets parent index of element at i
int parent(int i) const;
// Return element to the left of i
int left(int i) const;
// Return element to the right of i
int right(int i) const;
// Checks if an element has a left child
bool hasLeft(int i) const;
// Checks if an elemnt has a right child
bool hasRight(int i) const;
// "Max heapifies" an array
void maxHeapify(int i);
// builds a max heap
void buildMaxHeap();
// Allows comparison between results
bool operator==(const Heap& rhs);
bool operator==(const int* rhs);
// Useful for debugging. To use:
// Heap h;
// cout << h << endl;
friend std::ostream& operator<<(std::ostream& out, const Heap& h);
private:
// The array
int* A;
// Size of the array
int arraySize;
// The number of elements in the heap
int n;
};
// Useful for debugging. To use:
// Heap h;
// cout << h << endl;
std::string toDot(const Heap& h);
The code is called with I can include the entire main.cpp if needed but it has several hundred lines of just test cases that are commented out.
int A[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
Heap h(A, 8, 8);
if I comment out A = inArray; the program runs so I'm pretty confident that is where the issue is.
A is defined in Heap.h as `int* A;
Here is the full error:
*** Error in `./project': free(): invalid size: 0x00007ffd84786660 ***
Aborted (core dumped)
this is probably quite a simple issue, but I can't figure out what is causing this since I believe this should allocate an array of size inArraySize of type int and then assign the given array inArray to A.
Full disclosure: this is part of an assignment so feel free to just point me in the right direction, but my professor is fine with us using stackoverflow as long as we site it.
You're trying to copy an array, but assigning pointers like that is not how to do it. There are various ways.
Standard C++:
#include <algorithm>
std::copy(inArray, inArray + inArraySize, A);
Using standard containers:
#include <vector>
std::vector<int> A(inArray, inArray + inArraySize);
Old style C way
memcpy(A, inArray, sizeof(int) * inArraySize);
Doing:
A = new int[arraySize];
A = inArray;
Is like doing:
i = 5;
i = 6;
The second assignment overrides the first one.
Hence as a result, the member variable A is pointing to the same memory block pointed by the input argument inArray.
If you haven't dynamically allocated this memory block (with new), then you cannot dynamically deallocate it (with delete).
The lines
A = new int[arraySize];
A = inArray;
are cause of two problems.
There is a memory leak. The value returned by new int[arraySize] is lost and cannot be deallocated.
If you are calling delete [] A in the destructor, that would be cause of the second problem.
If inArray was dynamically allocated and deallocated in the calling function, you will be calling delete on the same pointer twice.
If inArray was an array created in the stack, calling delete on it is also a problem. delete can be called only on memory that was returned by call to new.
A = inArray; is not doing what you think it is doing. This line does not copy inArray into the memory you allocated for A. Instead it changes A to point to a new location (the address of inArray), causing the previously allocated memory to leak. Later on when you call delete on A you'll be trying to free memory at inArray's address.
If you just want to copy an array, you could do something like
A = new int[inArraySize];
for (i = 0; i < inArraySize; ++i)
A[i] = inArray[i];
Or better yet, with std::copy:
std::copy(inArray, inArray + inArraySize, A);
The Problem: When I attempt to assign an IntArray object by index I get the following error:
"Expression is not assignable."
The error is produced by the following line of code in iadrv.cpp:
IntArray a(10);
for(int i = a.low(); i <= a.high(); i++)
a[i] = i * 10;
I am able to assign an entire IntArray object to another like so, a = b;, however when a specific index is referred to the "expression is not assignable" error occurs.
EDIT: I removed the const declaration from most of the functions and I am not getting the "Expression is not assignable" error anymore. However, the setName now gives the error:
"ISO C++ 11 does not allow conversion from string literal to 'char *'"
This error is cause by the following code in iadrv.cpp:
a.setName("a");
Program Explanation:
I have written a class IntArray (in C++) in which the following operators are overloaded:
"[ ]" : allows index range checking
"=" : allows array assignment
"+" : allows the sum of two arrays to be assigned to a third array
"+=" : allows the sum of two arrays to be assigned to the first array
"<<" : allows the contents of an array to be output
The program also includes functions:
setName : sets the name of the IntArray object
getName : returns the name of the IntArray object
low : returns the smallest legal index
high : returns the largest legal index
length : returns the number of elements
A driver program (iadrv.cpp, iadrv.h) will run tests on the IntArray class (IntArray.cpp, IntArray.h) to determine if all operators were properly overloaded.
Note: that for each array test data, the driver will simply multiply the
array index by 10 immediately after each array is initialized or modified and output its contents. When the program encounters a run-time error, it should "simulate"a halt with appropriate diagnostics rather than actually halting the program.
The Code:
IntArray.h
// IntArray.h
#ifndef __IntArray__IntArray__
#define __IntArray__IntArray__
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
class IntArray {
private:
int a, b;
int size;
int * num;
char * name;
public:
IntArray(int start, int finish);
IntArray(int finish = 10);
IntArray(const IntArray &); //constructor copy
~IntArray();
int low() const;
int high() const;
char * getName() const;
//removed the const declaration from functions below
int & operator [] (int); //made to return int&
friend ostream & operator << (ostream &, IntArray &);
void setName(char *);
int length() const;
const IntArray & operator = (IntArray &);
const IntArray & operator + (IntArray &);
bool operator += (IntArray &);
};
#endif /* defined(__IntArray__IntArray__) */
IntArray.cpp
// IntArray.cpp
#include "IntArray.h"
#include <iostream>
#include <fstream>
using namespace std;
extern ofstream csis;
IntArray::IntArray(int start, int finish) {
if (start > finish) {
cout << "Simulating a halt.";
a = finish;
b = start;
}
else {
a = start;
b = finish;
}
size = b-a;
num = new int[size];
name = new char[1];
for (int i = 0; i < size; i++) {
num[i] = 0;
}
}
IntArray::IntArray(int finish) {
size = finish;
a = 0;
b = finish - 1;
num = new int[size];
name = new char[1];
for (int i = 0; i < size; i++) {
num[i] = 0;
}
}
IntArray::IntArray (const IntArray & right): size(right.size) {
num = new int[size];
name = new char[1];
for (int i = 0; i < size; i++) {
num[i] = right.num[i];
}
}
IntArray::~IntArray() {
delete[] num;
delete [] name;
}
int IntArray::low() const{
return a;
}
int IntArray::high() const{
return b;
}
char * IntArray::getName() const{
return name;
}
void IntArray::setName(char * n) {
name = n;
}
//removed const declarations
//made to return int&
int & IntArray::operator [] (int subscript) const{
if (subscript < a || subscript > b) {
cout << "subscript: " << subscript << endl;
cout << "Out of bound error. Simulating a halt." << endl;
return num[a];
}
return num[subscript-a];
}
int IntArray::length() const{
//b-a = size
return (b-a);
}
//removed const declarations
ostream & operator << (ostream & output, IntArray & array) {
for (int i = array.low(); i <= array.high(); i++) {
output << array.name << "[" << i << "] = " << array[i] << endl;
}
return output;
}
//removed const declarations
IntArray & IntArray::operator = (IntArray & right) {
if (length() == right.length()) {
for (int i = 0; i <= length(); i++) {
num[i] = right[right.low()+i];
}
return * this;
}
else {
delete [] num; //reclaim space
delete [] name;
size = right.length();
num = new int [size]; //space created
cout << "Different sized arrays. Simulating a hault" << endl;
}
return * this;
}
//removed const declarations
IntArray & IntArray::operator + (IntArray & right) {
int * ptr;
ptr = new int [right.length()];
if (length() == right.length()) {
for (int i = 0; i < length(); i++) {
ptr[i] = num[i] + right[right.low()+i];
}
}
return * this;
}
//removed const declarations
bool IntArray::operator += (IntArray & right) {
if (length() == right.length()) {
for (int i = 0; i <= right.length(); i++) {
num[i] += right[right.low()+i];
}
return true;
}
cout << "Could not add the sum of the arrays into first array. Simulating a halt." << endl;
return false;
}
iadrv.h
// iadrv.h
#ifndef p6_iadrv_h
#define p6_iadrv_h
#include "intarray.h"
int main();
void test1();
void wait();
#endif
iadrv.cpp
// iadrv.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdlib.h>
#include "iadrv.h"
using namespace std;
ofstream csis;
int main() {
csis.open("csis.dat");
test1();
csis.close();
}
void test1() {
system("clear");
cout << "1. Array declared with single integer: IntArray a(10);" << endl << endl;
csis << "1. Array declared with single integer: IntArray a(10);" << endl << endl;
IntArray a(10);
for(int i = a.low(); i <= a.high(); i++)
a[i] = i * 10;
a.setName("a");
cout << a << endl;
csis << a << endl;
wait();
}
DISCLAIMER: This program was written as a school assignment and has already been turned in to be graded. This was my first c++ program so I would like to understand my mistakes. Your help is sincerely appreciated.
You have defined your operator[] like this:
const int operator [] (int) const;
that second "const" means that inside that method you cannot modify your object.
So it will only work for getting values, but not for setting them.
Try to remove it and it should work.
EDIT: AS pointed to Bryan Chen, You also need to return a reference and non-const, like this:
int& operator [] (int subscript)
Now, looking more in depth at your code, that is not even enough, because you have this method:
ostream & operator << (ostream & output, const IntArray & array) {
for (int i = array.low(); i <= array.high(); i++) {
output << array.name << "[" << i << "] = " << array[i] << endl;
}
return output;
}
Look that you operator[] needs to work on a non-const IntArray, but in that method your variable "array" is const, so you need to rewrite a bit more of code.
Also, look for the same problem with the rest of the operators, remember: you make a method 'const' only if you don't plan to modify the object from inside that method, and you make a parameter 'const' only if you don't plan to modify that parameter.
Your existing operator does not allow the value to be changed, both because it returns an int by value and because the operator is declared const. You can't assign to a value, only to an object (which includes references, since a reference is just another name for an object).
To accomplish this you need to supplement your existing operator with another, non-const one that returns a reference to the (non-const) int:
int & operator[](int index);
Since this operator would return a reference, you can assign directly to the return value using the familiar a[b] = c syntax you desire to use.
You would not need to change your existing operator, but I would strongly recommend changing the return type from const int to just int -- you are returning by value anyway, so you are handing back a copy. It makes no sense for this to be const, and this may prevent the compiler from eliding copies in the case of more complex data types than int. (It doesn't really make much difference here, but I would avoid getting in the habit of returning both by value and const, since -- assuming the presence of a copy constructor -- the const qualifier can be removed anyway by simply copying the value again. Returning const copies usually provides no benefits while having several drawbacks.)
Since you also asked to point out your mistakes, I would like to comment on two things you should/could have done to make the code more simple:
First, the assignment operator could have been written like this:
IntArray& operator=(IntArray rhs)
{
std::swap(rhs.a, a);
std::swap(rhs.b, b);
std::swap(rhs.size, size);
std::swap(rhs.num, num);
std::swap(rhs.name, name);
return *this;
}
This works, since you have a copy constructor and destructor already defined for IntArray, and they hopefully work correctly. All the assignment operator is doing is creating a temporary object and swapping out its internals with the internals of the current object. Then the temporary dies with the "old data", while the new data is safely in the current object. This is called the copy/swap idiom.
Also note that a reference is returned that is non-const.
If you pass a const reference instead of an object, then the assignment operator is responsible for the initial copy made.
IntArray& operator=(const IntArray& orig)
{
IntArray rhs(orig);
std::swap(rhs.a, a);
std::swap(rhs.b, b);
std::swap(rhs.size, size);
std::swap(rhs.num, num);
std::swap(rhs.name, name);
return *this;
}
The former version may be faster, due to allowing the compiler to optimize the copy of the passed value. However the second form of passing a const reference is what is usually done -- note that the temporary object needs to be created inside the function before proceeding.
Second, your operator + can just use operator +=:
IntArray operator+(const IntArray& rhs)
{
IntArray temp(*this);
return temp += rhs;
}
All we did was create a temporary equal to the current object. Then we use += to add rhs and return the result. Nice and simple. Note that operator + returns a new IntArray object, not a const IntArray. In addition, operator += should return a reference to the current object, not bool.
To take advantage of this, your operator += should be rewritten thusly:
IntArray& operator+=(const IntArray& rhs)
{
//..your current code goes here:
//...
return *this;
}
Also, your operator += should not be "erroring out" like that. You need to make the class more robust by attempting to add two IntArrays that may not be the same size. If there really is an error throw an exception. Don't return a bool -- remove the return true; and return false; from the function altogether. Always return *this.
Hi there c++ programmers. I am encountering issue that i cant understand.I have strip the following program for readability reasons and left what i am having trouble with. I am trying to overload a + and = operators, but with dynamically created arrays. By themselves the + and = operator methods are producing the right results. However when i try to assign the result from the + operator to *poly3 i get "*poly3 need to be initialized" from the compiler. If i do initialize it nothing gets assign to it( i mean the result from +).
My question, what is the right way to do this. I need the result poly3 to be dynamic array or a pointer as well so i can use it latter.
Thanks a lot for the help in advance.
class Polynomial
{
private:
int *poly;
int size;
public:
Polynomial();
Polynomial(int);
Polynomial(string,int);
~Polynomial();
void setPoly(string);
int *getPoly() const;
Polynomial operator+(Polynomial&);
void operator=(const Polynomial&);
};
Polynomial::Polynomial(string polyInput, int s)
{
size = s+1;
poly = new int[size];
//set all coef position to 0
for(int i = 0; i < size; i++){
*(poly + i) = 0;
}
setPoly(polyInput);
}
Polynomial Polynomial::operator+(Polynomial &polyRight)
{
Polynomial *result = new Polynomial(size);
for(int i = 0; i < size; i++)
result->poly[i] = poly[i] + polyRight.poly[i];
return *result;
}
void Polynomial::operator=(const Polynomial &polyRight)
{
size = polyRight.size;
for(int i = 0; i < size; i++){
*(poly + i) = polyRight.poly[i];
}
}
int main()
{
int highestExp = 4;
Polynomial *poly1;
Polynomial *poly2;
Polynomial *poly3;// = new Polynomial(highestExp); // for the result
string input1,input2;
ifstream inputFile("data.txt");
getline(inputFile, input1);
getline(inputFile, input2);
poly1 = new Polynomial(input1,highestExp);
poly2 = new Polynomial(input2,highestExp);
*poly3 = *poly1 + *poly2;
system("pause");
return 0;
}
The assignment operator must return a reference to the instance assigned to:
Polynomial& operator=(const Polynomial&);
In the implementation, you should return *this;. You must also make sure that the implementation is robust against assignment of polynomials of different size. That doesn't seem to be the case currently.
Then, in main, poly3 is uninitialized. Just drop the pointers and instantiate all the polys as automatic storage, local variables in main():
Polynomial poly1(input1,highestExp);
Polynomial poly2(input2,highestExp);
Polynimial poly3 = poly1 + poly2;
As an aside, your operator+ has a memory leak. You should not be using new int it. Create a local Polynomial and return it.
Furthermore, you have no destructor taking care of releasing resources, so every instantiation of a Polynomial results in a memory leak. Your class has too many responsibilities: managing resources and being a polynomial. You should let a different class take care of the memory management. Use std::vector<int>, or, if this is an exercise, write your own dynamic array-like class, and use that inside Polynomial.
Pointers point to a memory location explicitly assigned to it.
Ptr* pt = new Ptr();//pt points to a valid address in memory
Ptr* pt;//pt has not yet been initialized
i.e. it is not pointing to any valid address. Using pt can cause unexpected behavior. By default pointers should point to NULL and they should be checked for !NULL and then used.
In above code Polynomial *poly3; is not pointing to any location and when we do
*pol3 we are actually dereferencing a location which had never been created.
When you do Polynomial *poly3 = new Polynomial(highestExp);, you are pointing poly3 to some valid location and hence *pol3 = *poly1 + *pol2 makes sense. But beware when you do a new for poly3 you are creating one more heap storage, so you have to make sure that you free all memory assigned on heap.
A better solution would be have your opertor + return a valid pointer and have it mapped to poly3 like this:
Polynomial* Polynomial::operator+(Polynomial &polyRight)
{
Polynomial *result = new Polynomial(size);
for(int i = 0; i < size; i++)
result->poly[i] = poly[i] + polyRight.poly[i];
return result;
}
//and in main
poly3 = (*poly1 + *poly2);
To start with:
// allow adding const
const Polynomial Polynomial::operator+(const Polynomial &polyRight) const
{
Polynomial result(size); // don't use a pointer
for(int i = 0; i < size; i++)
result.poly[i] = poly[i] + polyRight.poly[i];
return result;
}
make the return const to avoid the silliness of (A+B)=C;
Polynomial& Polynomial::operator=(const Polynomial &polyRight) // return a reference
{
size = polyRight.size;
for(int i = 0; i < size; i++){
*(poly + i) = polyRight.poly[i];
}
return *this; // allow chaining
}
Note that once you patch this up that you need to guard against A=A in operator =() :
if (this == &rhs)
{
// do stuff
}
return *this;
Here is quite a cleanup, with some slightly different functionality and better memory management. Since I didn't know the format of your input file, I've skipped the reading from file part, and just use a new constructor of the form Polynomial(countOfExponents, x0, x1, x2, x3, ... , xn)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdarg>
using namespace std;
class Polynomial
{
private:
int *poly;
int size;
public:
Polynomial() : size(0), poly(NULL) {}
Polynomial(int size, ... );
~Polynomial() { delete[](poly); }
void allocate(int size) {
if (NULL!=poly) {
delete[](poly);
}
Polynomial::size = size;
poly=new int[size];
}
Polynomial operator+(const Polynomial&) const;
Polynomial &operator=(const Polynomial&);
int exponent(int p) const {
return (p<size) ? poly[p] : 0;
}
string str() const;
};
Polynomial::Polynomial(int size, ...) : size(size) {
va_list varargs;
va_start(varargs, size);
poly = new int[size];
for (int i=0; i<size; i++) {
poly[i] = va_arg(varargs, int);
}
va_end(varargs);
}
Polynomial Polynomial::operator+(const Polynomial &polyRight) const
{
int newSize = max(size, polyRight.size);
Polynomial result;
result.allocate(newSize);
for(int i = 0; i < newSize; i++)
result.poly[i] = exponent(i) + polyRight.exponent(i);
return result;
}
Polynomial &Polynomial::operator=(const Polynomial &polyRight)
{
allocate(polyRight.size);
memcpy(poly, polyRight.poly, sizeof(int) * size);
return *this;
}
string Polynomial::str() const {
stringstream out;
for (int i=size-1; i>=0; i--) {
out << poly[i];
if (0<i) {
out << " ";
}
}
return out.str();
}
int main()
{
Polynomial one(3, 1, 2, 3);
Polynomial two(3, 2, 3, 4);
cout << one.str() << endl;
cout << two.str() << endl;
Polynomial three = one + two;
cout << three.str() << endl;
return 0;
}
Note that I'm also being careful not to address memory that might not exist when working with polynomials of different sizes. Accessing poly[n] on a polynomial with fewer than n exponents would cause trouble. Instead, use the exponent(n) function, which will return 0 for all exponents higher than those inside the polynomial.