C++ Copy Constructor and Assignment Operator Define
Could anybody help me correct the following copy constructor and assignment operator?
as you see, assignment operator seems to work well; I ran it and it works.
Do I define the assignment operator correct? Please let me know.
This crashes with the copy constructor...
How can I fix the copy constructor?
Please help me.
#include <iostream>
using namespace std;
class IntP
{
private:
unsigned int* counts;
unsigned int numP;
unsigned int size;
public:
IntP(); // Default Constructor
IntP(int n); // Constructor
IntP(const IntP& a); // Copy Constructor
IntP& operator= (const IntP& a); // Assignment Operator
~IntP(); // Destructor
void printIntP() const;
};
IntP::IntP() // Default Constructor
{
counts = new unsigned int[101] (); // initialize array of size 101 to all 0s
numP = 0;
size = 101;
}
IntP::IntP(int n) // Constructor
{
counts = new unsigned int[n+1] (); // initialize array of size n+1 to all 0s
counts[n] = 1;
numP = 1;
size = n+1;
}
// ????????????
//
IntP::IntP(const IntP& a) // Copy Constructor
{
this->size = a.size;
this->numP = a.numP;
for (int i=0; i < (int) this->size; i++)
this->counts[i] = a.counts[i];
}
// ???????????
// Correct Implementation?
// without delete operator, we have memory leak? but it compiles without error???
IntP& IntP::operator= (const IntP& a) // Assignment Operator
{
if (this != &a)
{
delete [] counts; // Get rid of old counts
size = a.size;
numP = a.numP;
counts = new unsigned int[size+1];
counts[size] = 1;
for (int i=0; i < (int) this->size; i++)
counts[i] = a.counts[i];
}
return *this;
}
IntP::~IntP() { delete [] counts; }
void IntP::printIntP() const
{
cout << "The size of array is " << this->size << endl;
cout << "The numP variable becomes " << this->numP << endl;
int i = 0;
while ( i != (int) this->size )
{
cout << counts[i];
if ( i != (int) this->size-1 ) cout << " , ";
i++;
}
cout << endl << endl;
}
int main (void)
{
IntP ip2(200);
IntP ip3;
ip3 = ip2;
IntP ip1(100);
cout << "Print out ip1 object after IntP ip1(100); " << endl;
ip1.printIntP();
IntP ip4(ip1);
cout << "Print out ip4 object after IntP ip4(ip1); " << endl;
ip4.printIntP();
system("pause"); return 0;
}
Your code crashes because of you don't allocate memory for counts in copy constructor.
IntP::IntP(const IntP& a) // Copy Constructor
{
//counts = new unsigned int[a.size] (); // Add this to allocate memory for counts
this->size = a.size;
this->numP = a.numP;
for (int i=0; i < (int) this->size; i++)
this->counts[i] = a.counts[i]; //counts is unitialized
}
Related
When i define dynamic array of objects, i want to choose one parameterized constructor for all objects in my array. without having to write for each object the chosen constructor like this
#include <iostream>
using namespace std;
class foo {
public:
foo ()
{
cout << "default constructor" << endl;
}
foo (int x)
{
cout << "parameterized constructor " << endl;
}
~foo ()
{
cout << "destructor" << endl;
}
};
int main (void)
{
int size = 3, parameter = 10;
foo *array;
array = new foo [size] { foo(parameter), foo(parameter), foo(parameter) };
cout << endl;
delete [] array;
return 0;
}
output
parameterized constructor
parameterized constructor
parameterized constructor
destructor
destructor
destructor
So, as you can see from the above code, I can choose parameterized constructor for each object in my array array = new foo [size] { foo(parameter), foo(parameter), foo(parameter) };.
However, if user inputs the size. same trick won't work
When I searched for solution, I found that I can do it with copy constructor like this
#include <iostream>
using namespace std;
class foo {
public:
foo ()
{
cout << "default constructor" << endl;
}
foo (int x)
{
cout << "parameterized constructor " << endl;
}
~foo ()
{
cout << "destructor" << endl;
}
};
int main (void)
{
int size = 3, parameter = 10;
foo *array;
array = new foo [size];
cout << endl;
for (int i = 0; i < size; i++)
array[i] = foo(parameter);
cout << endl;
delete [] array;
return 0;
}
output
default constructor
default constructor
default constructor
parameterized constructor
destructor
parameterized constructor
destructor
parameterized constructor
destructor
destructor
destructor
destructor
However, destructors are called for each object, and i don't want this
i just want to do it while allocating for the first time
Thanks in advance, and I hope that there's a solution.
The simplest solution to this problem would be to use std::vector which handles all those problems internally, e.g.:
#include <vector>
// skipping class declaration for brevity
int main (void)
{
int size = 3, parameter = 10;
std::vector<foo> array;
array.reserve(size);
cout << endl;
for (int i = 0; i < size; i++)
array.emplace_back(parameter);
cout << endl;
return 0;
}
However, if for some reason you want/need to do this by hand then you should be allocating a "raw buffer" and construct objects inside that buffer with placement new - this will however also require you to manually call the destructors
One possible example, doing everything "manually" could look like this
int main (void)
{
int size = 3, parameter = 10;
foo *array = reinterpret_cast<foo*>(new char[size * sizeof(foo)]);
cout << endl;
for (int i = 0; i < size; i++)
new (&array[i]) foo(parameter);
cout << endl;
for (int i = 0; i < size; i++)
array[i].~foo();
delete[] reinterpret_cast<char*>(array);
return 0;
}
An arguably cleaner solution is to use std::allocator and std::allocator_traits - this would look like this
#include <memory>
// skipping class declaration
int main (void)
{
std::allocator<foo> alloc;
using alloc_t = std::allocator_traits<decltype(alloc)>;
int size = 3, parameter = 10;
foo *array;
array = alloc_t::allocate(alloc, size);
cout << endl;
for (int i = 0; i < size; i++)
alloc_t::construct(alloc, &array[i], parameter);
cout << endl;
for (int i = 0; i < size; i++)
alloc_t::destroy(alloc, &array[i]);
alloc_t::deallocate(alloc, array, size);
return 0;
}
I would use a for loop :
array = new foo [size];
for(int i = 0; i < size; i++) {
array[i] = foo(parameter);
}
I don't see a simpler way to do it. And with this method, your size can be parametrized easily.
For your "destructor issue", use pointer on foo :
array = new *foo[size];
for(int i = 0; i < size; i++) {
array[i] = new foo(parameter);
}
But do not forget to delete each foo instance when needed :
for(int i = 0; i < size i++) {
delete array[i];
}
delete[] array;
I am trying to create a member function which print out the array that I control, but I am running into Seg fault. Any help would be really useful!
Here is my header file, all the code in there work except the last member function.
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
// operator overload
Array<T>& operator=(Array<T> &b){
if (a !=nullptr) delete[] a;
a = b.a;
b.a = nullptr;
length = b.length;
return *this;
}
//get the length of the array
int arraylength(){
return length;
}
//------------------This below is where I am having issue --------//
//print out the array
Array<T> printarray(){
for (int i = 0; i < length; i++){
cout << a[i];
}
}
};
int main();
#endif
This is my main file
#include <iostream>
#include "../include/array.h"
using namespace std;
int main(){
// initialize array
Array <int> a(5);
Array <int> b(5);
// put stuff into array
for (int i = 0; i< a.arraylength(); i++){
a[i] = i;
}
// set b = a using operator overload
b = a;
// print out the result b array
for (int i = 0; i < b.arraylength(); i++){
cout << b[i] << endl;
}
a.printarray();
return 0;
}
Again. Thank you for the help, I am quite new to C++ and mostly self taught.
In this statement
b = a;
you have called operator= in which a pointer of a object was set to nullptr, but in printArray you don't check if a is not null, so you are accesing data for null pointer, it is undefined behaviour. Add the condition to check if array is not empty:
void printarray(){
if (!a) return; // <- array is empty
for (int i = 0; i < length; i++){
cout << a[i];
}
}
Secondly, return type of printArray should be void, you don't return any value in this function.
You should fix printarray by changing the return type to void and making it a const member function.
void printarray() const {
for (int i = 0; i < length; i++){
cout << a[i];
}
}
However, that is not the main problem in your code. The main problem is that you are not following the The Rule of Three.
You don't have copy constructor.
You have a copy assignment operator but it is not implemented properly.
The line
b = a;
causes problems downstream that can be fixed by following The Rule of Three.
Here's an implementation of the copy assignment operator function that should work.
// Make the RHS of the operator a const object.
Array<T>& operator=(Array<T> const& b)
{
// Prevent self assignment.
// Do the real assignment only when the objects are different.
if ( this != &b )
{
if (a != nullptr)
{
delete[] a;
a = nullptr;
}
// This is not appropriate.
// a = b.a;
// b.a = nullptr;
// b needs to be left untouched.
// Memory needs to be allocated for this->a.
length = b.length;
if ( length > 0 )
{
a = new T[length];
// Copy values from b to this.
for (int i = 0; i < length; ++i )
{
a[i] = b.a[i];
}
}
}
return *this;
}
Please note that you should implement the copy constructor also, and then use the copy swap idiam to implment the assignment operator.
Very relevant: What is the copy-and-swap idiom?
I am trying to use the dynamic memory method instead of the vector method to add elements. Initially, the maximum size of the dynamic memory is set to 5. However, as soon as I try to increase more than the capacity of the current the dynamic memory, the elements of the 0th or 1st index loss their references.
The program works fine if I do not specify the size of the dynamic memory,
like: dynamic_memory = new int;. I am wondering why they lose their references
with the resize of the dynamic memory to more than the initial capacity.
PS: I am using Code::Block 16.01
Here is my program.
#include <iostream>
#include <cstdlib>
using namespace std;
class DynamicVector
{
public:
DynamicVector();
virtual ~DynamicVector();
void insertElement(int input);
int showCapacity();
int showSize();
void doubleSize(int * dynamic_memory);
friend ostream& operator << (ostream& outs, const DynamicVector obj);
private:
int * dynamic_memory;
int max_count; // this is similar to the capacity of the vector
int current_count; // this is similar to size of a vector
};
DynamicVector::DynamicVector()
{
max_count = 5;
dynamic_memory = new int[max_count];
current_count = 0;
}
DynamicVector::~DynamicVector()
{
delete [] dynamic_memory;
}
int DynamicVector::showCapacity(){
return max_count;
}
void DynamicVector::insertElement(int input)
{
if (current_count >= max_count)
doubleSize(dynamic_memory);
dynamic_memory[current_count] = input;
current_count++;
}
void DynamicVector::doubleSize(int * dynamic_memory){
int * tmp = new int[max_count];
for (int i = 0; i < max_count; i++)
tmp[i] = dynamic_memory[i];
delete [] dynamic_memory;
max_count = max_count * 2;
dynamic_memory = new int[max_count];
for (int i = 0; i < max_count; i++)
dynamic_memory[i] = tmp[i];
delete [] tmp;
}
int DynamicVector::showSize(){
return current_count;
}
ostream& operator <<(ostream& outs, const DynamicVector obj)
{
for (int i = 0; i < obj.current_count; i++)
outs << obj.dynamic_memory[i] << endl;
return outs;
}
int main()
{
DynamicVector v;
int numberOfIntendedElement = 11;
cout << "Previously, the capacity of vector was: " << v.showCapacity() << endl;
for (int i = 0; i < numberOfIntendedElement; i++)
v.insertElement(i);
cout << "The capacity of the new vector is: " << v.showCapacity() << endl;
cout << "The size of the new vector is: " << v.showSize() << endl;
cout << "The values in the dynamic vector are: \n" << v << endl;
return 0;
}
Result:
41107976
42075512
2
3
4
5
6
7
8
9
10
In
void doubleSize(int * dynamic_memory);
the dynamic_memory defined here shadows the member dynamic_memory; for comedic hi-jinks and undefined behaviour.
The local dynamic_memory is re-pointed at the new buffer, but the member dynamic_memory continues to point at the deleted original address after the function exits. This means that all subsequent inserts go into invalid memory, and Crom only knows what will happen after that.
Solution
Pass in nothing and use the member variable. Redefine the function as
void doubleSize();
Other problems are addressed in the comments and need to be fixed.
Thank you all for your valuable comments and suggestions, especially user4581301 for pointing a comedic hijinks and undefined behavior. After I redefined the function as void doubleSize(), it worked fine. Here is my final working code.
#include <iostream>
#include <cstdlib>
using namespace std;
class DynamicVector
{
public:
DynamicVector();
virtual ~DynamicVector();
void insertElement(int input);
int showCapacity();
int showSize();
void doubleSize();
friend ostream& operator << (ostream& outs, const DynamicVector obj);
private:
int * dynamic_memory;
int max_count; // this is similar to the capacity of the vector
int current_count; // this is similar to size of a vector
};
DynamicVector::DynamicVector()
{
max_count = 5;
dynamic_memory = new int[max_count];
current_count = 0;
}
DynamicVector::~DynamicVector()
{
delete [] dynamic_memory;
}
int DynamicVector::showCapacity(){
return max_count;
}
void DynamicVector::insertElement(int input)
{
if (current_count >= max_count)
doubleSize();
dynamic_memory[current_count] = input;
current_count++;
}
void DynamicVector::doubleSize(){
int * tmp = new int[max_count];
for (int i = 0; i < max_count; i++)
tmp[i] = dynamic_memory[i];
delete [] dynamic_memory;
max_count = max_count * 2;
dynamic_memory = new int[max_count];
for (int i = 0; i < max_count/2; i++)
dynamic_memory[i] = tmp[i];
delete [] tmp;
}
int DynamicVector::showSize(){
return current_count;
}
ostream& operator <<(ostream& outs, const DynamicVector obj)
{
for (int i = 0; i < obj.current_count; i++)
outs << obj.dynamic_memory[i] << endl;
return outs;
}
int main()
{
DynamicVector v;
int numberOfIntendedElement = 11;
cout << "Previously, the capacity of vector was: " << v.showCapacity() << endl;
for (int i = 0; i < numberOfIntendedElement; i++)
v.insertElement(i);
cout << "The capacity of the new vector is: " << v.showCapacity() << endl;
cout << "The size of the new vector is: " << v.showSize() << endl;
cout << "The values in the dynamic vector are: \n" << v << endl;
return 0;
}
Output
Previously, the capacity of vector was: 5
The capacity of the new vector is: 20
The size of the new vector is: 11
The values in the dynamic vector are:
0
1
2
3
4
5
6
7
8
9
10
I am fairly new to programming and our teacher had us create our own vector class. Everything works as needed, however once I hit the bottom and try to use the printV function, the size of the function is increased to a really large number instead of retaining the size of the vector. I will include all of the code below.
using namespace std;
class MyVector
{
private:
int vectorSize;
int maxCapacity;
int *myArray;
public:
//default constructor
//purpose: Initializes all variables
MyVector(void);
//Parameterized Constructor
//Purpose: creates a vector of capacity n
//parameters: int
MyVector(int);
//destructor
//Purpose: deletes and dynamically allocated storage
~MyVector(void);
// Overloaded assignment operator
// Purpose: to do assignment from one vector to another
// Parameters: a MyVector object
// Returns: A MyVector object
MyVector operator + (MyVector&);
// Copy constructor
// Purpose: Copy the data into this vector
// Parameters: a MyVector object
// Returns: none
MyVector(const MyVector&);
//size function
//purpose: gets the size of the vector
//returns: size
int size() const;
//capacity function
//purpose: gets the capacity of the vector
//returns: capacity
int capacity() const;
//clear function
//purpose: deletes all elements from the vector and resets its size to zero and capacity 2
//returns: nothing
void clear();
//push_back function
//purpose: adds an integer value at the end of the vector
//returns: nothing
void push_back(int n);
//at function
//purpose: returns the value of the element at position i in the vector
int at(int) const;
};
ostream& operator<<(ostream&, const MyVector&);
Here is the cpp file
#include "MyVector.h"
MyVector::MyVector(void)
{
maxCapacity = 2;
myArray = new int[maxCapacity];
vectorSize = 0;
}
MyVector::MyVector(int i)
{
maxCapacity = i;
myArray = new int[maxCapacity];
vectorSize = 0;
}
MyVector::~MyVector(void)
{
if (myArray != NULL);
{
delete [] myArray;
myArray = NULL;
}
}
MyVector MyVector::operator+(MyVector& rho)
{
if (this == &rho)
{
return *this;
}
delete [ ] this->myArray;
vectorSize = rho.vectorSize;
this->myArray = new int[maxCapacity];
for(int i = 0; i < maxCapacity; i++)
{
this->myArray[i] = rho.myArray[i];
}
return *this;
}
MyVector::MyVector(const MyVector& b)
{
maxCapacity = b.maxCapacity;
myArray = new int[maxCapacity];
for (int i = 0; i < maxCapacity; i++)
{
this->myArray[i] = b.myArray[i];
}
}
int MyVector::size() const
{
return vectorSize;
}
int MyVector::capacity() const
{
return maxCapacity;
}
void MyVector::clear()
{
delete [] myArray;
maxCapacity = 2;
myArray = new int[maxCapacity];
vectorSize = 0;
}
void MyVector::push_back(int add_Element)
{
if(vectorSize+1>maxCapacity)
{
maxCapacity = maxCapacity*2;
int* tmp = new int[maxCapacity];
for(int i=0; i <vectorSize; i++)
{
tmp[i] = myArray[i];
}
delete[] myArray;
myArray = tmp;
}
myArray[vectorSize] = add_Element;
vectorSize++;
}
int MyVector::at(int i) const
{
if(i >= vectorSize)
{
throw i;
}
else
{
return myArray[i];
}
}
ostream& operator<<(ostream& theStream, const MyVector& aVector)
{
for (int i = 0; i < aVector.size(); i++)
{
theStream << aVector.at(i);
}
return theStream;
}
And of course the Driver. I am unable to change the driver
#include <iostream>
#include "MyVector.h"
using namespace std;
// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);
int main( )
{
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);
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nCreating a vector Joe of size 4.";
MyVector joe( 4 );
cout << "\nPush 6 values into the vector.";
for (int i = 0; i < 6; i++)
joe.push_back(i * 3);
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
cout << "\nTest the overloaded assignment operator \"joe = sam\": ";
joe = sam;
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
// pass a copy of sam by value
printV(sam);//my problem is here! It changes the array size to a very large number
cout << endl;
system("PAUSE");
return 0;
}
void printV(MyVector v)
{
cout << "\n--------------------\n";
cout << "Printing a copy of a vector\n";
cout << v;
}
I think you are missing
vectorSize = b.vectorSize;
line in your copy constructor MyVector::MyVector(const MyVector& b)
When I run this code I get a bad_alloc error, Am I accessing the subscript operator wrong or something ? To me it makes sense that I go to the appropriate object, it gets returned and then the subscript operator should kick in ? By the way I want to use arrays and not vectors :)
class A{
public:
A(int size)
{
array = new int[size];
}
int& operator[](const int &i)
{
return array[i]
}
private:
int * array;
};
int main() {
A ** a = new A*[10];
for(int i = 0; i < 10; i++) {
a[i] = new A(10);
for(int l = 0; l < 10; l++) {
cout << a[i][l] << endl;
}
}
}
Thanks in advance
You need to dereference the pointer before you can call operator[]
cout << (*(a[i]))[l] << endl;
Here's what needs to happen, step by step:
A* pA = a[i];
A& rA = *pA;
int& val = rA[l];
cout << val;
Currently this happens:
A* pA = a[i];
A& ra = *(pA + l); // pA is indexed as an array of As - this is wrong
cout << ra; // invalid memory