Common print function for all variants of maps C++ STL - c++

I am brushing up some skills on C++ STL and I wrote a basic insertion/deletion code for maps.
Below is the code.
It is taking some inputs from user and inserting/deleting accordingly.
Very simple code.
But the issue is I have to write separate print functions for every map variant.
Is there anything I can do to make it common as we do in templates?
Any help would be highly appreciated.
#include <iostream>
#include <map>
#include <unordered_map>
using namespace std;
void print(const map<int, string>& mp)
{
cout << "Contents of map: { ";
for(auto& it: mp)
{
cout << it.first << " -> " << it.second << " ";
}
cout << "}" << endl;
}
void print(const multimap<int, string>& mp)
{
cout << "Contents of multi map: { ";
for(auto& it: mp)
{
cout << it.first << " -> " << it.second << " ";
}
cout << "}" << endl;
}
void print(const unordered_map<int, string>& mp)
{
cout << "Contents of unordered map: { ";
for(auto& it: mp)
{
cout << it.first << " -> " << it.second << " ";
}
cout << "}" << endl;
}
void print(const unordered_multimap<int, string>& mp)
{
cout << "Contents of unordered multi map: { ";
for(auto& it: mp)
{
cout << it.first << " -> " << it.second << " ";
}
cout << "}" << endl;
}
int main()
{
map<int, string> mp1;
multimap<int, string> mp2;
unordered_map<int, string> mp3;
unordered_multimap<int, string> mp4;
int value = 0;
string str;
cout << "Inserting..." << endl;
while(value >= 0)
{
cout << "Enter number: ";
cin >> value;
if(value >= 0)
{
cout << "Enter string: ";
cin >> str;
mp1.insert(pair<int, string>(value, str));
mp2.insert(pair<int, string>(value, str));
mp3.insert(pair<int, string>(value, str));
mp4.insert(pair<int, string>(value, str));
}
}
print(mp1);
print(mp2);
print(mp3);
print(mp4);
value = 0;
cout << "Removing..." << endl;
while(value >= 0)
{
cout << "Enter number: ";
cin >> value;
if(value >= 0)
{
// removing by value
mp1.erase(value);
mp2.erase(value);
mp3.erase(value);
mp4.erase(value);
}
}
print(mp1);
print(mp2);
print(mp3);
print(mp4);
return 0;
}

Well, yes, that is, indeed, what templates are used for, right?
template<typename T>
void print(const T& mp)
{
cout << "Contents of map: { ";
for(auto& it: mp)
{
cout << it.first << " -> " << it.second << " ";
}
cout << "}" << endl;
}
This'll work as long as only maps, or reasonable facsimiles thereof, are passed to print() (and both keys and values in the maps have a working << overload). Otherwise, it might become necessary to use SFINAE or C++20 concepts to constrain overload resolution.

Related

Using unique_ptr as a member class and with list

I recently made an application with 1 superclass and 2 subclasses. The main idea of it is storing information in 3 different list. My question is, can you only use 1 list for all 3 classes? Even though the 2 subclasses have some extra members. Someone told me that you could use unique_ptr as a member of the superclass and make only 1 list. I have read about it on the internet, but I can't quite get it. Any suggestions? Thank you for your time.
class Student {
std::string Name;
std::string Pinfo;
std::map < std::string, float > Ngradelist;
public:
std::string getName() {return Name;}
std::string getPinfo() {return Pinfo;}
virtual void InsertGradeList(std::string a, float b) {
for(auto& it : Ngradelist)
Ngradelist.insert(std::pair <std::string, float > (a,b));
}
Student( std::string n, std::string p, std::map < std::string, float > Ng) :
Name(std::move(n)), Pinfo(std::move(p)), Ngradelist(std::move(Ng)) {}
virtual void Display() {
std::cout << "Name: " << Name << std::endl;
std::cout << "Personal information: " << Pinfo << std::endl;
std::cout << "NCourse:" << std::endl;
for(auto& it : Ngradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
}
};
class HWStudent : public Student {
std::string FieldOfWork;
std::map<std::string, float> HWgradelist;
public:
void InsertGradeList(std::string a, float b) override{
for (auto &it : HWgradelist)
HWgradelist.insert(std::pair<std::string, float>(a, b));
}
HWStudent(std::string n, std::string p, std::map<std::string, float> Ng, std::string f,
std::map<std::string, float> HWg) : Student(std::move(n), std::move(p), std::move(Ng)),
FieldOfWork(std::move(f)), HWgradelist(std::move(HWg)) {}
void Display() override {
Student::Display();
std::cout << "Field of Work: " << FieldOfWork << std::endl;
std::cout << "HWCourse:" << std::endl;
for(const auto& it : HWgradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
}
};
class SWStudent : public Student {
std::map<std::string, float> SWgradelist;
std::list < std::string > Languages;
public:
void InsertGradeList(std::string a, float b) override {
for (const auto &it : SWgradelist)
SWgradelist.insert(std::pair<std::string, float>(a, b));
}
SWStudent(std::string n, std::string p, std::map<std::string, float> Ng, std::list < std::string > l,
std::map<std::string, float> SWg) : Student(std::move(n), std::move(p), std::move(Ng)),
Languages(std::move(l)), SWgradelist(std::move(SWg)) {}
void Display() override {
Student::Display();
std::cout << "SWCourse:" << std::endl;
for(const auto& it : SWgradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
std::cout << "SW Languages:" << std::endl;
for(const auto& it : Languages)
std::cout << " " << it << std::endl;
}
};
std::list < Student > listaStudenti;
std::list < HWStudent > HWlistaStudenti;
std::list < SWStudent > SWlistaStudenti;
void InsertListaStudenti(unsigned short option) {
unsigned short numbers;
std::string name , pinfo, course, fieldofwork, hwcourse, swcourse;
std::string language;
float grade = 0, hwgrade, swgrade;
std::list < std::string > languagelist;
if(option == 1) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
Student student(name, pinfo, {{course, grade}});
listaStudenti.push_back(student);
}
if(option == 2) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
std::cout << "Insert hwcourse: ";
std::cin >> hwcourse;
std::cout << "Insert hwgrade: ";
std::cin >> hwgrade;
std::cout << "Insert fieldofwork: ";
std::cin >> fieldofwork;
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork,{{hwcourse, hwgrade}});
HWlistaStudenti.push_back(hwstudent);
}
if(option == 3) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
std::cout << "Insert swcourse: ";
std::cin >> swcourse;
std::cout << "Insert swgrade: ";
std::cin >> swgrade;
std::cout << "How many languages: ";
std::cin >> numbers;
for(auto it = 0;it < numbers; ++it) {
std::cout << "Insert language: ";
std::cin >> language;
languagelist.push_back(language);
}
SWStudent swstudent(name, pinfo, {{course, grade}},languagelist,{{swcourse, swgrade}});
SWlistaStudenti.push_back(swstudent);
}
}
int main() {
unsigned short option = 10;
while(option != 0) {
std::cout << "1.Add student." << std::endl;
std::cout << "2.Add HW student." << std::endl;
std::cout << "3.Add SW student." << std::endl;
std::cout << "4.Display Student." << std::endl;
std::cout << "5.Display HW Student." << std::endl;
std::cout << "6.Display SW Student." << std::endl;
std::cout << "0 is for exit." << std::endl;
std::cout << "Option is : ";
std::cin >> option;
switch (option) {
case 0 : {
std::cout <<" You chose to leave.";
exit;
break;
}
case 1 : {
InsertListaStudenti(option);
break;
}
case 2 : {
InsertListaStudenti(option);
break;
}
case 3: {
InsertListaStudenti(option);
break;
}
case 4: {
for(auto &it : listaStudenti)
it.Display();
break;
}
case 5: {
for(auto &it : HWlistaStudenti)
it.Display();
break;
}
case 6: {
for(auto &it : SWlistaStudenti)
it.Display();
break;
}
}
}
}
You can indeed have
std::list<std::unique_ptr<Student>> students;
instead of
std::list<Student> listaStudenti;
std::list<HWStudent> HWlistaStudenti;
std::list<SWStudent> SWlistaStudenti;
with insertion similar to
Student student(name, pinfo, {{course, grade}});
students.push_back(std::make_unique<Student>(std::move(student)));
// or std::make_unique<Student>(name, pinfo, std::map<std::string, float>{{course, grade}})
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork, {{hwcourse, hwgrade}});
students.push_back(std::make_unique<HWStudent>(std::move(hwstudent));
instead of
Student student(name, pinfo, {{course, grade}});
listaStudenti.push_back(student);
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork,{{hwcourse, hwgrade}});
HWlistaStudenti.push_back(hwstudent);
Issue would be with your "filtering":
for (auto& student : SWlistaStudenti) {
student.Display();
}
becomes
for (auto& studentPtr : SWlistaStudenti) {
if (auto ptr = dynamic_cast<SWStudent*>(studentPtr.get())) ptr->Display();
}
but (to show only regular students (not HW/SW))
for(auto& student : listaStudenti) { student.Display(); }
becomes
for (auto& studentPtr : students) {
if (!dynamic_cast<SWStudent*>(studentPtr.get())
&& !dynamic_cast<HWStudent*>(studentPtr.get())) {
studentPtr->Display();
}
}
One list allows to treats them equality BTW:
To display all students:
for (auto& studentPtr : students) { studentPtr->Display(); }
instead of
for (auto& student : listaStudenti) { student.Display(); }
for (auto& student : HWlistaStudenti) { student.Display(); }
for (auto& student : SWlistaStudenti) { student.Display(); }

memory leaks in c++

#pragma once
#ifndef SDDS_GIFT_H
#define SDDS_GIFT_H
#include <iostream>
namespace sdds
{
const int MAX_DESC = 15;
const double MAX_PRICE = 999.999;
const int MAX_WRAP = 20;
struct Gift
{
char m_description[MAX_DESC];
double m_price;
int m_units;
int m_wrapLayers;
struct Wrapping* m_wrap;
};
struct Wrapping
{
char* m_pattern;
};
void gifting(char*);
void gifting(double&);
void gifting(int&);
bool wrap(Gift& theGift);
bool unwrap(Gift& theGift);
void gifting(Gift& theGift);
void display(const Gift& theGift);
}
#endif
<pre><code>
#include <iostream>
#include "Gift.h"
using namespace std;
namespace sdds
{
void gifting(char* m_description) // sending info
{
cout << "Enter gift description: ";
cin.width(MAX_DESC + 1);
cin >> m_description;
}
void gifting(double& m_price)
{
cout << "Enter gift price: ";
cin >> m_price;
while (m_price > MAX_PRICE || m_price < 0)
{
cout << "Gift price must be between 0 and " << MAX_PRICE << std::endl;
cout << "Enter gift price: ";
cin >> m_price;
}
}
void gifting(int& m_units)// gifting function
{
cout << "Enter gift units: ";
cin >> m_units;
while (m_units < 1)
{
cout << "Gift units must be at least 1" << std::endl;
cout << "Enter gift units: ";
cin >> m_units;
};
}
bool wrap(Gift& m_wrap) {
if (m_wrap.m_wrapLayers > 0) {
cout << "Gift is already wrapped!" << endl;
return false;
}
else {
cout << "Wrapping gifts..." << endl;
cout << "Enter the number of wrapping layers for the Gift: ";
cin >> m_wrap.m_wrapLayers;
while (m_wrap.m_wrapLayers < 1) {
cout << "Layers at minimum must be 1, try again." << endl;
cout << "Enter the number of wrapping layers for the Gift: ";
cin >> m_wrap.m_wrapLayers;
}
int i = 0;
m_wrap.m_wrap = new Wrapping[MAX_WRAP + 1];
for (i = 0; i < m_wrap.m_wrapLayers; i++) {
m_wrap.m_wrap->m_pattern = new char[MAX_WRAP + 1];
cout << "Enter wrapping pattern #" << i + 1 << ": ";
cin >> m_wrap.m_wrap->m_pattern;
} // I put struct in a structure
return true;
}
delete[]m_wrap.m_wrap;
m_wrap.m_wrap = nullptr;
}
bool unwrap(Gift& g_unwrap) // unwrap function
{
if (g_unwrap.m_wrapLayers > 0) {
cout << "Gift being unwrapped." << endl;
g_unwrap.m_wrapLayers = 0;
g_unwrap.m_wrap->m_pattern = nullptr;
return true;
}
else
{
cout << "Gift isn't wrapped! Can't unwrap." << endl;
return false;
}
}
void display(const Gift& theGift)
{
cout << "Gift Details:" << endl;
cout << " Description: " << theGift.m_description << endl;
cout << " Price: " << theGift.m_price << endl;
cout << " Units: " << theGift.m_units << endl;
if (theGift.m_wrap == nullptr) // this part seems like a problem
{
cout << "Unwrapped" << endl;
}
else
{
int i = 0;
cout << "Wrap Layers: " << theGift.m_wrapLayers << endl;
for (i = 0; i < theGift.m_wrapLayers; i++) {
cout << "Wrap #" << i + 1 << ": " << theGift.m_wrap[i].m_pattern << endl;
}
}
}
void gifting(Gift& gift) //last function
{
cout << "Preparing a gift..." << endl;
gifting(gift.m_description);
gifting(gift.m_price);
gifting(gift.m_units);
wrap(gift);
}
}
</code></pre>
/***********************************************************************
// Workshop 2: Dynamic Memory & Function Overloading
// Version 2.0
// Date 2020/05/05
// Author Michael Huang
// Description
// Tests Gift module and provides a set of TODOs to complete
// which the main focuses are dynamic memory allocation
//
/////////////////////////////////////////////////////////////////
***********************************************************************/
#include <iostream>
#include "Gift.h"
#include "Gift.h" // intentional
using namespace std;
using namespace sdds;
void printHeader(const char* title)
{
char oldFill = cout.fill('-');
cout.width(40);
cout << "" << endl;
cout << "|> " << title << endl;
cout.fill('-');
cout.width(40);
cout << "" << endl;
cout.fill(oldFill);
}
<pre><code>
int main() {
Gift g1; // Unwrapped Gift
{
printHeader("T1: Checking Constants");
cout << "MAX_DESC: " << sdds::MAX_DESC << endl;
cout << "MAX_PRICE: " << sdds::MAX_PRICE << endl;
cout << "MAX_WRAP: " << sdds::MAX_WRAP << endl;
cout << endl;
}
{
printHeader("T2: Display Wrapped Gift");
gifting(g1.m_description);
gifting(g1.m_price);
gifting(g1.m_units);
cout << endl;
g1.m_wrap = nullptr;
g1.m_wrapLayers = 0;
display(g1);
cout << endl;
}
{
printHeader("T3: Wrap a gift");
if (wrap(g1))
cout << "Test succeeded!";
else
cout << "Test failed: wrapping didn't happen!" << endl;
cout << endl << endl;
}
{
printHeader("T4: Re-wrap a gift");
cout << "Attempting to rewrap the previous Gift: "
<< g1.m_description << endl;
if (wrap(g1) == false)
cout << "Test succeeded!";
else
cout << "Test failed: gift it's already wrapped, cannot wrap again!";
cout << endl << endl;
}
{
printHeader("T5: Unwrap a gift");
cout << "Attempting to unwrap the previous gift: "
<< g1.m_description << endl;
if (unwrap(g1))
cout << "Test succeeded!";
else
cout << "Test failed: you should be able to unwrap!";
cout << endl << endl;
}
{
printHeader("T6: Unwrap again");
cout << "Attempting to un-unwrap the previous gift: "
<< g1.m_description << endl;
if (!unwrap(g1))
cout << "Test succeeded!";
else
cout << "Test failed: you should not be able to unwrap again!";
cout << endl << endl;
}
Gift g2; // Unwrapped Gift
{
printHeader("T7: Prepare another gift");
g2.m_wrap = nullptr;
g2.m_wrapLayers = 0;
gifting(g2);
cout << endl;
display(g2);
cout << endl;
}
{
printHeader("T8: Unwrap the second gift");
unwrap(g2);
}
return 0;
}
Output matches perfectly but I don't know why memory leaks.. please help me. I am doubting my wrap part but I think there must be something else since deallocation seems fine.
I tried my best but I still cannot see which part is wrong.
I cannot see why my deallocation does not work I tried changing it so many times but nothing works.
On this line:
m_wrap.m_wrap->m_pattern = new char[MAX_WRAP + 1];
You allocate memory, but later you only:
delete[]m_wrap.m_wrap;
Also in your for loop you allocate memory, then get some input and store that inside the pointer, as a memory address. Should you ever dereference that, you will invoke undefined behavior, in practice that may likely will a segfault. You should consider rewriting at least that part from scratch.

Searching for a vector inside another vector

I want to search thorough a vector to see if an element appears. Once this element appears along with others, i want to re-search through the original to see if this second element appears else where within the vector. The end result should show the first element being found and then the information of where the second element appears.
void searchband()
{
ifstream artist("newartist.txt");
string SBand;
cout << "Please enter the band you want to seach" << endl;
cin >> SBand;
system("CLS");
while (artist >> forname >> surname >> bandnum)
{
band.clear();
for (int i = 0; i < bandnum; i++)
{
string tmp;
artist >> tmp;
band.push_back(tmp);
}
artist >> role;
if (find(band.begin(), band.end(), SBand) != band.end())
{
cout << forname << " " << surname << endl;
cout << "Played for: ";
ostream_iterator<string> output_iterator(cout, " ");
copy(band.begin(), band.end(), output_iterator);
cout << " " << endl;
cout << " " << endl;
newband = band;
}
if (find(band.begin(), band.end(), newband) != band.end())
{
cout << forname << " " << surname << endl;
cout << "Played for: ";
ostream_iterator<string> output_iterator(cout, " ");
copy(band.begin(), band.end(), output_iterator);
cout << " " << endl;
cout << " " << endl;
}
system("pause");
cin.get();
main();
}
}
This gets the error code
error C2678: binary '==' : no operator found which takes a left-hand operand of type std::basic_string<char,std::char_traits<char>,std::allocator<char>> (or there is no acceptable conversion)
I think it may be because
vector<string> = newband
but that is the only way i can think of to pass the vector information over is to another vector
std::find_first_of does what you are looking for:
Searches the range [first, last) for any of the elements in the range [s_first, s_last).
Example (also taken from cppreference):
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{0, 2, 3, 25, 5};
std::vector<int> t{3, 19, 10, 2};
auto result = std::find_first_of(v.begin(), v.end(), t.begin(), t.end());
if (result == v.end()) {
std::cout << "no elements of v were equal to 3, 19, 10 or 2\n";
} else {
std::cout << "found a match at "
<< std::distance(v.begin(), result) << "\n";
}
}

terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check

Why am I getting this error on executing my code? In it I am trying to implement an adjacency list for a graph.
#include <iostream>
#include<vector>
#include<stdio.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
int n,k,i,m=0;
cin >> n;
vector<int> mv[n];
for(i=0;i<n;i++)
{
for(m=0;m<n;m++)
{
scanf("%d",&k);
if(k>0)
mv[i].push_back(k);
}
}
cout << mv[0].at(0) << " ";
cout << mv[0].at(1) << " ";
cout << mv[0].at(2) << " ";
cout << mv[1].at(1) << " ";
cout << mv[2].at(1) << " ";
cout << mv[3].at(0) << " ";
}
return 0;
}
You iterate through elements without making sure you're in your vectors bounds...
Replace
cout << mv[0].at(0) << " ";
cout << mv[0].at(1) << " ";
cout << mv[0].at(2) << " ";
cout << mv[1].at(1) << " ";
cout << mv[2].at(1) << " ";
cout << mv[3].at(0) << " ";
By:
for(i=0;i<n;i++)
{
for ( size_t pos = 0; pos != mv[i].size(); ++pos )
cout << mv[i].at(pos) << " ";
}
and it should work better then...

Why won't my ofstream work when I put it outside my while statement?

Every time I do anything, and my while(1) gets called in my main function, my file gets cleared. It's driving me crazy. I've tried EVERYTHING. I try to put my ofstream out("data.dat"); outside the while(1) statement so it isn't called everytime but then nothing is written to the file like the ofstream isn't even working!
I've tried to make the ofstream static, so it isn't called over and over again like:
static ofstream open("data.dat");
That doesn't work.
And like I said, when I put the ofstream OUTSIDE the while statement, nothing is written to the file. Like:
ofstream out("data.dat");
while (1)
{
string line = "";
cout << "There are currently " << structList.size() << " items in memory.";
cout << endl << endl;
cout << "Commands: " << endl;
cout << "1: Add a new record " << endl;
cout << "2: Display a record " << endl;
cout << "3: Edit a current record " << endl;
cout << "4: Delete a record " << endl;
cout << "5: Save current information " << endl;
cout << "6: Exit the program " << endl;
cout << endl;
cout << "Enter a command 1-6: ";
getline(cin , line);
int rValue = atoi(line.c_str());
system("cls");
switch (rValue)
{
case 1:
structList = addItem(structList);
break;
case 2:
displayRecord(structList);
break;
case 3:
structList = editRecord(structList);
break;
case 4:
deleteRecord(structList);
break;
case 5:
if (!structList.size()) { cout << "There are no items to save! Enter one first!" << endl << endl; system("pause"); system("cls"); break; }
writeVector(out , structList);
break;
case 6:
return 0;
default:
cout << "Command invalid. You can only enter a command number 1 - 6. Try again. " << endl;
}
out.close();
}
And can someone tell me why my check to prevent reading of a empty file won't work?
My Check:
bool checkFileEmpty()
{
ifstream in("data.dat");
if (in.peek() == in.eofbit)
{
return true;
}
return false;
}
I am so sick and tired of my program crashing on startup over and over again because my vector is getting set to a size of 200 million. I've tried a BUNCH of stuff for this... none of it works... Please GOD someone help me with both of these! I've been up for 18 hours working on this ( all night yes ) and i'm ALMOST done. I'm begging you....
My Code:
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace System;
using namespace std;
#pragma hdrstop
bool isValidChoice(int size, int choice);
bool checkFileEmpty();
template<typename T>
void writeVector(ofstream &out, const vector<T> &vec);
template<typename T>
vector<T> readVector(ifstream &in);
template<typename T>
vector<T> addItem(vector<T> &vec);
template<typename T>
void printItemDescriptions(vector<T> &vec);
template<typename T>
int displayRecord(vector<T> &vec);
template<typename T>
vector<T> editRecord(vector<T> &vec);
template<typename T>
vector<T> deleteRecord(vector<T> &vec);
struct InventoryItem {
string Description;
int Quantity;
int wholesaleCost;
int retailCost;
string dateAdded;
} ;
int main(void)
{
cout << "Welcome to the Inventory Manager extreme! [Version 1.0]" << endl;
ifstream in("data.dat");
if (in.is_open()) { cout << "File \'data.dat\' has been opened successfully." << endl; } else { cout << "Error opening data.dat" << endl;}
cout << "Loading data..." << endl;
vector<InventoryItem> structList = readVector<InventoryItem>( in );
cout <<"Load complete." << endl << endl;
in.close();
while (1)
{
string line = "";
cout << "There are currently " << structList.size() << " items in memory.";
cout << endl << endl;
cout << "Commands: " << endl;
cout << "1: Add a new record " << endl;
cout << "2: Display a record " << endl;
cout << "3: Edit a current record " << endl;
cout << "4: Delete a record " << endl;
cout << "5: Save current information " << endl;
cout << "6: Exit the program " << endl;
cout << endl;
cout << "Enter a command 1-6: ";
getline(cin , line);
int rValue = atoi(line.c_str());
system("cls");
ofstream out("data.dat");
switch (rValue)
{
case 1:
structList = addItem(structList);
break;
case 2:
displayRecord(structList);
break;
case 3:
structList = editRecord(structList);
break;
case 4:
deleteRecord(structList);
break;
case 5:
if (!structList.size()) { cout << "There are no items to save! Enter one first!" << endl << endl; system("pause"); system("cls"); break; }
writeVector(out , structList);
break;
case 6:
return 0;
default:
cout << "Command invalid. You can only enter a command number 1 - 6. Try again. " << endl;
}
out.close();
}
system("pause");
return 0;
}
template<typename T>
void writeVector(ofstream &out, const vector<T> &vec)
{
out << vec.size();
for(vector<T>::const_iterator i = vec.begin(); i != vec.end(); i++)
{
out << *i;
}
cout << "Save completed!" << endl << endl;
}
ostream &operator<<(ostream &out, const InventoryItem &i)
{
out << i.Description << ' ';
out << i.Quantity << ' ';
out << i.wholesaleCost << ' ' << i.retailCost << ' ';
out << i.dateAdded << ' ';
return out;
}
istream &operator>>(istream &in, InventoryItem &i)
{
in >> i.Description;
in >> i.Quantity;
in >> i.wholesaleCost >> i.retailCost;
in >> i.dateAdded;
return in;
}
template<typename T>
vector<T> readVector(ifstream &in)
{
size_t size;
if (checkFileEmpty())
{
size = 0;
} else {
in >> size;
}
vector<T> vec;
vec.reserve(size);
for(unsigned int i = 0; i < size; i++)
{
T tmp;
in >> tmp;
vec.push_back(tmp);
}
return vec;
}
template<typename T>
vector<T> addItem(vector<T> &vec)
{
system("cls");
string word;
unsigned int number;
InventoryItem newItem;
cout << "-Add a new item-" << endl << endl;
cout << "Enter the description for the item: ";
getline (cin , word);
newItem.Description = word;
cout << endl;
cout << "Enter the quantity on hand for the item: ";
getline (cin , word);
number = atoi(word.c_str());
newItem.Quantity = number;
cout << endl;
cout << "Enter the Retail Cost for the item: ";
getline (cin , word);
number = atoi(word.c_str());
newItem.retailCost = number;
cout << endl;
cout << "Enter the Wholesale Cost for the item: ";
getline (cin , word);
number = atoi(word.c_str());
newItem.wholesaleCost = number;
cout << endl;
cout << "Enter current date: ";
getline (cin , word);
newItem.dateAdded = word;
vec.push_back(newItem);
return vec;
}
template<typename T>
void printItemDescriptions(vector<T> &vec)
{
int size = vec.size();
if (size)
{
cout << "---------------------------------" << endl;
cout << "| ~ Item Descriptions ~ |" << endl;
cout << "---------------------------------" << endl;
cout << "*********************************" << endl;
for (int i = 0 ; i < size ; i++)
{
cout << "(" << i+1 << ")" << ": " << vec[i].Description << endl;
}
cout << "*********************************" << endl << endl;
}
}
template<typename T>
int displayRecord(vector<T> &vec)
{
string word = "";
string quit = "quit";
int choice = 1;
int size = vec.size();
if (size)
{
printItemDescriptions(vec);
cout << endl;
while (1)
{
cout << "Type \"exit\" to return to the Main Menu." << endl << endl;
cout << "Enter \"list\" to re-display the items." << endl << endl;
cout << endl;
cout << "Pick the number of the item you would like to display: ";
getline (cin , word);
if (convertToLower(word) == "exit") { system("cls"); return 0; }
if (convertToLower(word) == "list") { system("cls"); displayRecord(vec); }
choice = atoi(word.c_str());
choice -= 1;
if (isValidChoice(size, choice))
{
system("cls");
cout << endl << "[Item (" << choice << ") details] " << endl << endl;
cout << "******************" << endl;
cout << "* Description * " << vec[choice].Description << endl;
cout << "******************" << endl << endl;
cout << "******************" << endl;
cout << "*Quantity On Hand* " << vec[choice].Quantity << endl;
cout << "******************" << endl << endl;
cout << "******************" << endl;
cout << "* Wholesale Cost * " << vec[choice].wholesaleCost << endl;
cout << "****************** " << endl << endl;
cout << "******************" << endl;
cout << "* Retail Cost * " << vec[choice].retailCost << endl;
cout << "****************** " << endl << endl;
cout << "******************" << endl;
cout << "* Data Added * " << vec[choice].dateAdded << endl;
cout << "****************** " << endl << endl;
} else { system("cls"); cout << "That item doesn't exist!" << endl; cout << "Pick another item or enter \"list\" to see available items." << endl << endl; }
}
} else { cout << "There are currently no items to display." << endl << endl; system("pause"); system("cls"); return 0; }
return 1;
}
bool isValidChoice(int size, int choice)
{
for (int i = 0 ; i <= size ; i++)
{
if (choice == i) { return true; }
}
return false;
}
string convertToLower(string word)
{
for (unsigned int i = 0 ; i < word.size() ; i++)
{
word[i] = tolower(word[i]);
}
return word;
}
bool checkFileEmpty()
{
ifstream in("data.dat");
if (in.peek() == in.eofbit)
{
return true;
}
return false;
}
template<typename T>
vector<T> editRecord(vector<T> &vec)
{
string word;
int choice;
printItemDescriptions(vec);
cout << "Choose item to edit: ";
getline ( cin, word );
choice = atoi(word.c_str());
system("cls");
unsigned int number;
InventoryItem newItem;
cout << "-Edit an item-" << endl << endl;
cout << "Enter the description for the item: ";
getline (cin , word);
vec[choice-1].Description = word;
cout << endl;
cout << "Enter the quantity on hand for the item: ";
getline (cin , word);
number = atoi(word.c_str());
vec[choice-1].Quantity = number;
cout << endl;
cout << "Enter the Retail Cost for the item: ";
getline (cin , word);
number = atoi(word.c_str());
vec[choice-1].retailCost = number;
cout << endl;
cout << "Enter the Wholesale Cost for the item: ";
getline (cin , word);
number = atoi(word.c_str());
vec[choice-1].wholesaleCost = number;
cout << endl;
cout << "Enter current date: ";
getline (cin , word);
vec[choice-1].dateAdded = word;
system("cls");
cout << "Item edited successfully! " << endl;
return vec;
}
template<typename T>
vector<T> deleteRecord(vector<T> &vec)
{
if (!vec.size()) { cout << "There are no items to delete!" << endl << endl; return vec; }
printItemDescriptions(vec);
string word;
int choice;
cout << "Choose item to delete: ";
getline( cin, word);
choice = atoi(word.c_str());
vec.erase (vec.begin()+choice-1);
return vec;
}
You'd better move the ofstream openning and closing inside case 5.
Here you create a new file at each while iteration.
case 5:
{
ofstream out("data.dat");
writeVector(out , structList);
out.close();
}
break;
ofstream out("data.dat");
Opens the file for writing. By default, it will start at the very beginning wiping out anything that was there previously. First, use a different output file than the file you are reading from.
Try adding the close to the case 6 statements:
case 6:
out.close();
return 0;
I'm pretty sure the close isn't getting called as the return will exit main before getting to that statement. With the file unclosed you are left with a buffer unflushed and I suspect that will leave the data unwritten.
You should move the open to before the while loop and also remove the out.close() from the while loop as it's going to close the file after the first menu selection.
To check if a file is empty or cannot be opened
bool IsEmpty( const std::string & filename ) {
std::ifstream ifs( filename.c_str() );
if ( ifs.is_open() ) {
std::string line;
return ! std::getline( ifs, line );
}
else {
return true;
}
}