C++ SimpleVector Using Templates - c++

I am trying to get my program to let the user choose which data type they would like to use, 1 for int, 2 for double, and 3 for string. Take that type and make it the type for our dynamic array. Allow the user to say how many inputs of the data they would like, and then allow the user to enter the data.
For some reason not clear to me, my program crashes right after the user enters any number for the type they want to use.
(I also have some other methods to implement, but I wanted to get this fixed first. So that's why there are unused methods.)
Is there something I am not seeing here? Any help is greatly appreciated. Thank you so much.
#include <iostream>
#include <cstdlib>
using namespace std;
template <class T>
class SimpleVector
{
private:
T *tempPointer;
int lengthOfArray;
public:
SimpleVector();
~SimpleVector();
SimpleVector(int lengthOfArray);
SimpleVector(const SimpleVector& copy);
int getArraySize();
T getElementAt(int n);
T & operator[](int index);
};
// default no-arg constructor
template <class T>
SimpleVector<T>::SimpleVector()
{
tempPointer = NULL;
lengthOfArray = 0;
}
// destructor for deallocating memory
template <class T>
SimpleVector<T>::~SimpleVector()
{
delete [] tempPointer;
}
// single argument constructor
template <class T>
SimpleVector<T>::SimpleVector(int dynamicArray)
{
lengthOfArray = dynamicArray;
tempPointer = new T[lengthOfArray];
}
// Copy constructor
template <class T>
SimpleVector<T>::SimpleVector(const SimpleVector& copy)
: lengthOfArray(copy.lengthOfArray), tempPointer(new int[copy.lengthOfArray])
{
int newSize = copy->size();
tempPointer = new T[newSize];
for(int i = 0; i < newSize; i++){
tempPointer[i] = copy.tempPointer[i];
}
}
// gets the size of the dynamic array
template <class T>
int SimpleVector<T>::getArraySize()
{
return lengthOfArray;
}
// returns element from array at specified position
template <class T>
T SimpleVector<T>::getElementAt(int n)
{
return *(tempPointer + n);
}
// returns reference to the element in array indexed by subscript
template <class T>
T & SimpleVector<T>::operator[](int index)
{
return this->tempPointer[index];
}
int main()
{
int dataType;
int dataSize = 0;
char keepGoing;
do{
cout << "What type of data do you want to enter?\n(1 for integer, 2 for double and 3 for strings)" << endl;
cin >> dataType;
cout << "How many data inputs? " << endl;
cin >> dataSize;
SimpleVector <int> list1(dataSize);
if (dataType == 1) {
SimpleVector <int> list1(dataSize);
}
else if (dataType == 2) {
SimpleVector <double> list1(dataSize);
}
else if (dataType == 3) {
SimpleVector <string> list1(dataSize);
}
else {
cout << " That's not an available option. Bye! " << endl;
return 0;
}
cout << "Please enter the data:" << endl;
for (int i = 0; i <= dataSize; i++) {
cin >> list1[i];
}
cout << "Do you want to enter data again? (y/n?)" << endl;
cin >> keepGoing;
}while((keepGoing == 'Y') | (keepGoing == 'y'));
return 0;
}

For some reason not clear to me, my program crashes right after the user enters any number for the type they want to use.
I would suggest, that you test your program multiple times, when you are writing it. As #Jarod42 said in his comment, your if statements don't really do much, because your
SimpleVector <type> list1(dataSize);
gets destroyed after { }.
So basically whatever number user types, your SimpleVector will always be of the type int.
Now when you try to:
cout << "Please enter the data:" << endl;
for (int i = 0; i <= dataSize; i++) {
cin >> list1[i];
}
you are calling function:
template <class T>
T & SimpleVector<T>::operator[](int index)
{
return this->tempPointer[index];
}
At this point, you pointer is pointing to NULL, but you are trying to access [index] of your pointer, which is pointing to NULL. That's why you program crashes.
EDIT:
I'm not sure if this is what you want, but i'll give it a try :
do{
cout << "What type of data do you want to enter?\n(1 for integer, 2 for double and 3 for strings)" << endl;
cin >> dataType;
cout << "How many data inputs? " << endl;
cin >> dataSize;
if (dataType == 1) {
SimpleVector <int> list1(dataSize);
cout << "Please enter the data:" << endl;
for (int i = 0; i <= dataSize; i++) {
cin >> list1[i];
}
}
else if (dataType == 2) {
SimpleVector <double> list1(dataSize);
cout << "Please enter the data:" << endl;
for (int i = 0; i <= dataSize; i++) {
cin >> list1[i];
}
}
else if (dataType == 3) {
SimpleVector <string> list1(dataSize);
cout << "Please enter the data:" << endl;
for (int i = 0; i <= dataSize; i++) {
cin >> list1[i];
}
}
else {
cout << " That's not an available option. Bye! " << endl;
return 0;
}
cout << "Do you want to enter data again? (y/n?)" << endl;
cin >> keepGoing;
}while((keepGoing == 'Y') | (keepGoing == 'y'));

Related

String error when expanding a dynamic array

I'm having a problem with trying to append an extra element to a dynamic array. I know I can use vectors, but for academic purposes, I have to use arrays.
#include <iostream>
using namespace std;
template <class T>
class MyList
{
protected:
T* elems;
int itsSize;
public:
MyList(int itsSize):itsSize(itsSize)
{
elems = new T[itsSize];
}
~MyList()
{
delete [] elems;
}
int getSize()
{
return itsSize;
}
virtual void addElem(){}
virtual void getElem(){}
};
template <class T>
class MyStack : public MyList<T>
{
int counter;
public:
MyStack(int size):MyList<T>::MyList(size){counter=0;}
void addElem()
{
T* tmp = new T[counter+1];
for (int i = 0; i<counter+1; i++)
tmp[i] = MyList<T>::elems[i];
counter++;
delete [] MyList<T>::elems;
MyList<T>::elems = tmp;
cin >> MyList<T>::elems[counter-1];
if(cin.fail())
{
cin.clear();
string line;
getline(cin, line);
throw "Wrong String Input--> will enter 0";
}
}
void getElem()
{
for(int i=counter-1; i>=0; i--)
{
cout << "Element-->" << MyList<T>::elems[i] << endl;
}
}
};
int main()
{
int storeChoice;
cout << "Would you like to store integers, strings or rectangles (1,2, or 3)?" << endl;
cin >> storeChoice;
if(storeChoice==1)
{
MyStack<int> numList(1);
cout << "Enter num:";
numList.addElem();
bool choiceAddLoop = true;
while(choiceAddLoop == true)
{
try
{
char choiceAdd;
cout << "Would you like to enter another elem?(y/n)" << endl;
cin >> choiceAdd;
if(choiceAdd=='y')
{
try
{
cout << "Enter num:";
numList.addElem();
}
catch(const char* wrongInput)
{
cout << wrongInput << endl;
}
}
else if(choiceAdd=='n')
{
choiceAddLoop=false;
break;
}
else
throw "Invalid Input.";
}
catch(const char* invalidChoice)
{
cout << invalidChoice;
}
}
cout << endl << "All Elements" << endl;
numList.getElem();
}
else if(storeChoice==2)
{
MyStack<string> stringList(1);
cout << "Enter string:";
stringList.addElem();
bool choiceAddLoop = true;
while(choiceAddLoop == true)
{
try
{
char choiceAdd;
cout << "Would you like to enter another elem?(y/n)" << endl;
cin >> choiceAdd;
if(choiceAdd=='y')
{
cout << "Enter string:";
stringList.addElem();
}
else if(choiceAdd=='n')
{
choiceAddLoop=false;
break;
}
else
throw "Invalid Input.";
}
catch(const char* invalidChoice)
{
cout << invalidChoice;
}
}
cout << endl << "All Elements" << endl;
stringList.getElem();
}
}
When I select the first choice ( integer ) the code will work:
Would you like to store integers, strings or rectangles (1,2, or 3)?
1
Enter num:22
Would you like to enter another elem?(y/n)
y
Enter num:3
Would you like to enter another elem?(y/n)
n
All Elements
Element-->3
Element-->22
Process returned 0 (0x0) execution time : 5.162 s
Press any key to continue.
A problem occurs in the second choice (string):
Would you like to store integers, strings or rectangles (1,2, or 3)?
2
Enter string:hello
Would you like to enter another elem?(y/n)
y
Enter string:terminate called after throwing an instance of 'std::length_error'
what(): basic_string::_M_create
Process returned 3 (0x3) execution time : 6.761 s
Press any key to continue.
It's the same code for both, why does it work only with integers?
The error happens when you call MyStack<T>::addElem(). When you copy the elements from the old array to the new array your loop should stop at counter, not counter+1. Correct version:
for (int i = 0; i<counter; i++)
tmp[i] = MyList<T>::elems[i];
Accessing MyList<T>::elems[counter], which is out of bounds, results in undefined behavior. For the int-case you were just lucky that the data currently stored there could be correctly interpreted as integer, with std::string you had less luck. So the random data which you wanted to interpret as std::string caused the error you got.
Live demo

Error in converting class to template class

Code is a little long because I can't really trace the source of the error, so I'm not sure how much more I can remove (still new to C++ templates)
Already omitted are member functions and methods that I've also converted to templates, I don't think they're relevant for the error.
Below was a given class that I've been converting to an abstract template class, when compiled, I get the following compile-time error:
1.cpp:116:3: error: no matching function for call to 'testPFArrayD'
testPFArrayD();
1.cpp:87:6: note: candidate template ignored: couldn't infer template
argument 'T' void testPFArrayD()
Line 166 is the Main() call for the function testPFArrayD(). The actual purpose of the class isn't very important in this case, I just need to know the issue in converting it to a template.
The full-length, original source code (not converted to a template) for the class is here
#include <iostream>
using namespace std;
template <typename T>
class PFArrayD
{
public:
PFArrayD();
PFArrayD(int capacityValue);
PFArrayD(const PFArrayD& pfaObject);
void addElement(T element);
bool full() const { return (capacity == used); }
int getCapacity() const { return capacity; }
int getNumberUsed() const { return used; }
void emptyArray() { used = 0; }
double& operator[](T index);
PFArrayD& operator =(const PFArrayD& rightSide);
~PFArrayD();
private:
double *a;
int capacity;
int used;
};
template <typename T>
PFArrayD<T>::PFArrayD() :capacity(50), used(0)
{
a = new T[capacity];
}
template <typename T>
void testPFArrayD()
{
int cap;
cout << "Enter capacity of this super array: ";
cin >> cap;
PFArrayD() temp (cap); //?????????????????
cout << "Enter up to " << cap << " nonnegative numbers. \n";
cout << "Place a negative number at the end. \n";
double next;
cin >> next;
while ((next >= 0) && (!temp.full()))
{
temp.addElement(next);
cin >> next;
}
cout << "You entered the following " << temp.getNumberUsed() << " numbers:\n";
int index;
int count = temp.getNumberUsed();
for (index = 0; index < count; index++)
cout << temp[index] << " ";
cout << endl;
cout << "(plus a sentinel value.)\n";
}
int main()
{
cout << "This program tests the class PFArrayD.\n";
char ans;
do {
testPFArrayD();
cout << "Test again? (y/n) ";
cin >> ans;
} while ((ans == 'y') || (ans == 'Y'));
//system("pause");
return 0;
}

What is a deleted function, and why only my functions that I pass files into are considered deleted? [duplicate]

This question already has answers here:
Using fstream Object as a Function Parameter
(3 answers)
Closed 6 years ago.
#include <bits/stdc++.h>
using namespace std;
class contact {
private:
vector< pair<string, int> > contact_info;
public:
void add_contact(string contact_name, int contact_number) {
contact_info.push_back(make_pair(contact_name, contact_number));
sort(contact_info.begin(),contact_info.end());
}
void edit_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
cout << "Enter the new number: ";
cin >> contact_info[found_at].second;
}
void show_all() {
for (unsigned int i =0; i < contact_info.size(); i++) {
cout << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void delete_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
contact_info.erase(contact_info.begin()+found_at);
}
void writeFile(ofstream contact_file) {
for (unsigned int i =0; i < contact_info.size(); i++) {
contact_file << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void readFile(ifstream contact_file) {
string input;
while (!contact_file.eof()) {
contact_file >> input;
size_t pos = input.find(" ");
string name = input.substr(0,pos);
string number_str = input.substr(pos);
int number = stoi(number_str) ;
contact_info.push_back(make_pair(name,number));
}
}
};
int main()
{
int choice;
ifstream contacts_file_read;
contacts_file_read.open("contacts.txt");
ofstream contacts_file_write;
contacts_file_write.open("contacts.txt");
bool in_prog = true;
contact contacts;
string name;
int number;
while (in_prog) {
cout << "1. Add contacts" << endl
<< "2. Edit contact" << endl
<< "3. Delete contact" << endl
<< "4. Show all" << endl
<< "5. exit" << endl;
cout << "Your choice: ";
cin >> choice;
contacts.readFile(contacts_file_read);
if (choice == 1) {
cout << "Enter name & number separated by a space: ";
cin >> name >> number;
contacts.add_contact(name, number);
} else if (choice == 2) {
cout << "Enter name of contacts to be edited: ";
cin >> name;
contacts.edit_contact(name);
} else if (choice == 3) {
cout << "Enter name of contact to be deleted: ";
cin >> name;
contacts.delete_contact(name);
} else if (choice == 4) {
contacts.show_all();
} else if(choice == 5) {
contacts.writeFile(contacts_file_write);
} else {
cout << "Wrong choice" << endl;
}
}
return 0;
}
So, I was asked in my programming class to make a phone book application in C++ using only objects, so this is my attempt at it.
All functions are good, I did recompile the program after finishing each function at it gave me 0 errors, however whenever I try to call writeFile or readFile function that were previously working fine, now the compiler gave me an error of "error: use of deleted functions... "
I don't know what are deleted functions and why only functions that take file objects as an argument are treated as such.
Can anyone please help?
Thanks.
Objects of type std::ifstream are not copyable -- indeed, the object represents the unique handle of an open file, and it would be difficult to conceptualize what it would mean to copy such unique responsibility.
Indeed, this inability to copy an object is encoded by making the copy constructor deleted, which causes the error that you see when you do attempt to copy it.
Your code should pass the original ifstream, not a copy (by taking a reference parameter):
void readFile(ifstream & contact_file)
// ^^^^^^^^^^

Using variables declared inside an if else construct later in the program results in an undeclared identifier error

This program is pretty self explanatory, so I won't really get into the purpose of what its for.
My main problem right now is on lines 82, 89, 95, and 101, I'm getting "Undeclared Identifier" errors for "arr" and "input" when i compile.
Is this because I declared them inside of an if else if construct, and if so, is there any way to get around this. Thanks for any help in advance!!!!
Here is the code
#include <iostream>
#include <string>
using namespace std;
template<class T> void selectionSort(T arr[], T num)
{
int pos_min;
T temp;
for (int i = 0; i < num - 1; i++)
{
pos_min = i;
for (int j = i + 1; j < num; j++)
{
for (arr[j] < arr[pos_min])
{
pos_min = j;
}
}
if (pos_min != i)
{
temp = arr[i];
arr[i] = arr[pos_min];
arr[pos_min] = temp;
}
}
}
int main()
{
char check = 'C';
while (toupper(check) != 'Q')
{
char dataType;
int num = 0;
cout << "What kind of data do you want to sort?" << endl;
cout << " For integer enter i, for string enter s, for character enter c. ";
cin >> dataType;
//User input dataType
if (toupper(dataType) == 'I')
{
int arr[100];
int input;
cout << " You've chosen Integer dataType" << endl;
}
else if (toupper(dataType) == 'S')
{
string arr[100];
string input;
cout << " You've chosen String dataType" << endl;
}
else if(toupper(dataType) == 'C')
{
char arr[100];
char input;
cout << " You've chosen Character dataType" << endl;
}
else
{
cout << "Not a recognizable dataType. Shuting down..." << endl;
return -1;
}
//User input # of num
cout << "How many num will be sorted? ";
cin >> num;
for (int i = 0; i < num; i++)
{
cout << "Enter an input of the dataType you selected: ";
cin >> input;
arr[i] = input;
}
//Display user input
cout << "The data as you entered it: ";
for (int i = 0; i < num; i++)
{
cout << arr[i];
cout << " ";
}
cout << endl;
//Sort user input by calling template functon selectionSort
selectionSort(arr, num);
//Display sorted user input
cout << "After sorting your data by calling selectionSort: ";
for (int i = 0; i < num; i++)
{
cout << arr[i];
cout << " ";
}
cout << endl;
//Query user to quit or continue
cout << " Would you like to continue? Enter 'Q'. Enter anything else to continue.";
cin >> check;
}
return 0;
}
It is because you declared them inside an if/else block. Once the block completes, these variable go out of scope and are no longer accessible.
One way around this would be to always read in the input as character data, then convert it into the specified type after the fact. See atoi for how to convert from char to int.
A variable can never have unknown type. Even inside a template, the type of every variable is fixed for any particular instantiation.
Which suggests a solution. All the code that works on a variable with multiple types can be placed into a template function.
You may find the template syntax for passing an arbitrary length array of arbitrary element type useful:
template<typename T, size_t N>
void func1( T (&arr)[N] )
{
//...
}
But you really don't even need to pass the array. Just pass a type, and use that type when creating the array inside the function.
template<typename T>
void process_it()
{
T arr[100];
T input;
// now work on them
}
Either way, you'll need to call this function from inside all the if/else branches, where the exact type is known.

push_back() not working for custom data type (template class)

Apparently push_back() is not working for my custom data class T. On compilation I get the following error:
error: no matching function for call to ‘Vector::push_back(int&)’
Could someone explain to me why that is? Thank you.
#include <std_lib_facilities>
#include <numeric>
#include <vector>
#include <string>
// vector<int> userin;
// int total;
// bool success;
class T
{
public:
void computeSum(vector<T> userin, int sumamount, T& total, bool& success);
void getData(vector<T> userin);
};
template <class T>
void computeSum(vector<T> userin, int sumamount, T& total, bool& success)
{
if (sumamount < userin.size()){
success = true;
int i = 0;
while (i<sumamount){
total = total + userin[i];
++i;
}
} else {
success = false;
cerr << "You can not request to sum up more numbers than there are.\n";
}
}
template <class>
void getData(vector<T> userin)
{
cout << "Please insert the data:\n";
int n;
do{
cin >> n;
userin.push_back(n);
} while (n);
cout << "This vector has " << userin.size() << " numbers.\n";
}
int helper()
{
cout << "Do you want help? ";
string help;
cin >> help;
if (help == "n" || help == "no"){
return 0;
}else{
cout << "Enter your data. Negative numbers will be added as 0. Ctrl-D to finish inputing values.\n";
}
}
int main()
{
helper();
getData(userin);
cout << "How many numbers would you like to sum?";
int sumamount;
cin >> sumamount;
computeSum(userin, sumamount);
if (success = true) {
cout << "The sum is " << total << endl;
} else {
cerr << "Oops, an error has occured.\n";
}
cout << endl;
return 0;
}
Outside some flagrantly offensive issues (e.g. it should be template <class T>, not template<class>), the real problem is that vector expects you to push back objects of type T. It looks like you are reading in with type int and pushing. Try:
template <class>
void getData(vector<T> userin)
{
cout << "Please insert the data:\n";
T n;
do{
cin >> n;
userin.push_back(n);
} while (n);
cout << "This vector has " << userin.size() << " numbers.\n";
}
The problem is this line:
userin.push_back(n);
where n is an int. push_back is expecting something of type T.
I'm also not sure what the point of class T is in this case.