Overloading operator =, error in reading string - c++

I am trying to write an overload to the = operator so that it allows you directly assign one student object to another student object. So it will copy all the private data members. Here is what I have so far.
.h
#ifndef PROJECT3HEADER_H
#define PROJECT3HEADER_H
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Student
{
public:
Student();
void Setlname(string lname);
void Setfname(string fname);
void SetAverage(float Average);
void SetLettergrade(char lettergrade);
void SetTestScore1(float score1);
void SetTestScore2(float score2);
void SetTestScore3(float score3);
void SetTestScore4(float score4);
void SetTestScore5(float score5);
string Getlname()const;
string Getfname()const;
float GetAverage()const;
char GetLetterGrade()const;
float GetScore1()const;
float GetScore2()const;
float GetScore3()const;
float GetScore4()const;
float GetScore5()const;
//void operator = (const Student & rhs);
Student operator=(const Student &rhs);
private:
string lname,fname;
float testScore[5];
float Average;
char lettergrade;
};
ostream & operator << (ostream &, const Student & pt);
//istream& operator >> (istream& in, Student& pt);
#endif
Studentmem.cpp
#include "Project3Header.h"
#include <iostream>
#include <string>
using namespace std;
Student::Student()
{
lname="";
fname="";
Average=0;
lettergrade=' ';
testScore[0]=0,testScore[1]=0,testScore[2]=0,testScore[3]=0,testScore[4]=0;
}
void Student::Setlname(string lname1){
lname=lname1;
}
void Student::Setfname(string fname1){
fname=fname1;
}
void Student::SetAverage(float average1){
Average=average1;
}
void Student::SetLettergrade(char lettergrade1){
lettergrade=lettergrade1;
}
void Student::SetTestScore1(float score1){
testScore[0]=score1;
}
void Student::SetTestScore2(float score2){
testScore[1]=score2;
}
void Student::SetTestScore3(float score3){
testScore[2]=score3;
}
void Student::SetTestScore4(float score4){
testScore[3]=score4;
}
void Student::SetTestScore5(float score5){
testScore[4]=score5;
}
string Student::Getlname()const {
return lname;
}
string Student::Getfname()const {
return fname;
}
float Student::GetAverage() const{
return Average;
}
char Student::GetLetterGrade()const{
return lettergrade;
}
float Student::GetScore1() const{
return testScore[0];
}
float Student::GetScore2() const{
return testScore[1];
}
float Student::GetScore3() const{
return testScore[2];
}
float Student::GetScore4() const{
return testScore[3];
}
float Student::GetScore5() const{
return testScore[4];
}
Student Student::operator=(const Student &rhs){
lname = rhs.lname;
fname = rhs.fname;
for (int i = 0; i < 5; i++){
testScore[i] = rhs.testScore[i];
}
return *this;
}
std::ostream& operator<<(std::ostream& out, Student const& obj)
{
out << "Lname: " << obj.Getlname() << "\n";
out << "fname: " << obj.Getfname() << "\n";
out << "Average: " << obj.GetAverage() << "\n";
out << "Grade: " << obj.GetLetterGrade() << "\n";
return out;
}
But when I try to use it in the main I get an error... error reading characters of string.
here is a little of my main
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include "Project3Header.h"
using namespace std;
//Tyler Smith
void StdInfo(Student array[], int size);
Student * MakeStudentArray(int size);
int main(){
ifstream inData;
int size = 0;
int highsize = 0;
char data[65535];
inData.open("F:\\grade.dat");
if (!inData)
{
cout << "Error opening file.\n";
cout << "Perhaps the file is not where indicated.\n";
return 1;
}
while (inData.getline(data, 65535)) {
size++;
}
inData.close();
cout << size;
Student s1;
Student * ptArr;
ptArr = MakeStudentArray(size);
for (int i = 0; i < size; i++){
ptArr[i]= s1;
}
StdInfo(ptArr,size);
/* for (int i = 0; i < size; i++){
cout << ptArr[i].Getlname() << ptArr[i].Getfname(); //<< ptArr[i].Get() << endl;
}*/
cout << ptArr[2].Getfname();
return 0;
}
Student * MakeStudentArray(int size)
{
return new Student[size];
}
void StdInfo(Student array[], int size){
ifstream in;
in.open("F:\\grade.dat");
string fname1,lname1="";
int Score1, Score2, Score3, Score4, Score5=0;
for (int i = 0; i < size; i++) {
in >> lname1;
in >> fname1;
in >> Score1;
in >> Score2;
in >> Score3;
in >> Score4;
in >> Score5;
array[i].Setlname(lname1);
array[i].Setfname(fname1);
array[i].SetTestScore1(Score1);
array[i].SetTestScore2(Score2);
array[i].SetTestScore3(Score3);
array[i].SetTestScore4(Score4);
array[i].SetTestScore5(Score5);
array[i] = array[i + 1];
//for (int j = 0; j < 5; j++) {
//in >> array[i].testScore[j];
//}
}
}
When I try it simply will not work. When I do it in debug mode it stops at the overloading operator and stays "rhs error reading characters of string"

The essense of your problem is not the (unconventional) assignment operator, but the MakeStudentArray function.
I hardcoded the size to 10, rather than reading it from a file, and used
Student * MakeStudentArray(int size)
{
return new Student[size];
}
taking care to call delete [] ptArr; after I was done in main (worrying about exceptions as I did) and all was well.
Your version allocates Students (maybe all over the heap), rather than an array.
If I change the question code you posted in main to
for (int i = 0; i < size; i++){
ptArr[i].operator= (s1);
//^------- you said 0, right?
}
then I get a problem. This is because the for loop assumes the "array" is contiguous, but your function newed an array of points, not an array of Students, so it walks into goodness only knows where when it tries to loop over the "array".
Using my suggestion version should solve the problem, since it allocates an array using new[size] and also makes it easier to delete.
Edit 1:
With the rest on main now posted, perhaps you do keep trying to set ptArr[0] several times in the loop, but then calling StdInfowill try to walk an "array" and will give you the error. If you wish to index into an array, using [] it must be contiguous, so the allocation function, MakeStudentInfo will still be the cause of the problem.
Edit2:
Now there is even more code, look at your StdInfo function. Without the extra details it does this:
for (int i = 0; i < size; i++) {
//...
array[i] = array[i + 1];
}
What are you trying to achieve here? It looks like set the current array[i] to something we haven't got to yet. Once i gets to size i+1 will be off the end of your array.
Removing that line would be a good idea.

The assignment operator should return a reference to the assigned object, not a copy. Also think about using the copy & swap idiom
Student& Student::operator=(const Student &rhs){

Related

Identifier not found - error C3861 in Visual Studio 2019

I have a problem with my code. Unfortunately, when compiling I get these errors all the time. What can this be caused by and how to fix it?
error C3861: 'print': identifier not found
My code:
main.cpp
#include "pojazdy.h"
#include <iostream>
using namespace std;
int main()
{
Pojazdy** poj;
int size{ 0 }, index{ 0 };
Petla(poj, size);
print(poj, size);
wyrejestruj(poj,size,0);
print(poj, size);
wyrejestruj(poj,size);
return 0;
}
pojazdy.h
#ifndef pojazdy_h
#define pojazdy_h
#include <iostream>
#include <cstdlib>
using namespace std;
class Pojazdy
{
public:
string typ;
string marka;
string model;
string z_dod;
int ilosc;
int cena;
void dodaj();
void d_pojazd(Pojazdy**& pojazdy, int& size);
void wyrejestruj(Pojazdy**& pojazdy, int& size, int index);
void print(Pojazdy** pojazdy, int size);
void Petla(Pojazdy**& p, int& size);
//void wyswietl();
int get_ilosc() { return ilosc; }
string get_typ() { return typ; }
string get_marka() { return marka; }
string get_model() { return model; }
int get_cena() { return cena; }
void set_ilosc(int x);
};
#endif
pojazdy.cpp
#include "pojazdy.h"
#include <iostream>
using namespace std;
void Pojazdy::set_ilosc(int x) { ilosc = x; }
void Pojazdy::dodaj()
{
cout << "DODAWANIE POJAZDU..." << endl;
cout << "Podaj typ pojazdu:";
cin >> typ;
cout << "Podaj marke pojazdu: ";
cin >> marka;
cout << "Podaj model pojazdu: ";
cin >> model;
cout << "Dodaj cene pojazdu: ";
cin >> cena;
}
void Petla(Pojazdy**& p, int& size) {
char z_dod;// = 'N';
do {
d_pojazd(p, size); //odpowiada za dodawnie
p[size - 1]->dodaj();
cout << "Czy chcesz zakonczyc dodawanie? Jesli tak, wcisnij Y/N: ";
cin >> z_dod;
} while (z_dod == 'N' || z_dod == 'n');//while (p[size]->z_dod == "N" ||p[size]->z_dod == "n");
}
void print(Pojazdy** pojazdy, int size) {
std::cout << "====================================" << std::endl;
for (int i{ 0 }; i < size; i++)
std::cout << "Typ: " << pojazdy[i]->get_typ() << " Marka: " << pojazdy[i]->get_marka() << " Model: " << pojazdy[i]->get_model() << " Cena: " << pojazdy[i]->get_model() << std::endl;
}
void wyrejestruj(Pojazdy**& pojazdy, int& size) {
for (size_t i{ 0 }; i < size; i++)
delete pojazdy[i];
delete[] pojazdy;
size = 0;
pojazdy = NULL;
}
void wyrejestruj(Pojazdy**& pojazdy, int& size, int index) {
if (index < size) {
Pojazdy** temp = new Pojazdy * [size - 1];
short int j{ -1 };
for (size_t i{ 0 }; i < size; i++) {
if (i != index) {
j++;
temp[j] = pojazdy[i];
}
}
delete[] pojazdy;
--size;
pojazdy = temp;
}
else
std::cout << "Pamiec zwolniona!" << std::endl;
}
void d_pojazd(Pojazdy**& pojazdy, int& size) {
Pojazdy** temp = new Pojazdy * [size + 1];
if (size == 0)
temp[size] = new Pojazdy;
else {
for (int i{ 0 }; i < size; i++)
temp[i] = pojazdy[i];
delete[] pojazdy;
temp[size] = new Pojazdy;
}
++size;
pojazdy = temp;
}
I used #ifndef, #define, #endif and #pragma once, but none of them work. I will be really grateful for every code, I am already tired of this second hour. And forgive the non-English variables and function names for them - it's university code, so I didn't feel the need.
Move the functions below outside the class declaration.
void wyrejestruj(Pojazdy**& pojazdy, int& size, int index);
void print(Pojazdy** pojazdy, int size);
void Petla(Pojazdy**& p, int& size);
Or make them static and call like Pojazdy::print(poj, size);.
You declared a non-static member function print in the class definition
class Pojazdy
{
public:
// ...
void print(Pojazdy** pojazdy, int size);
//...
but you are trying to call it as a stand-alone function in main
print(poj, size);
So the compiler issues an error.
The declaration of the function as a stand alone function that at the same time is its definition in the file pojazdy.cpp is not visible in the module with main because this module includes only the header with the class declaration.
You should decide whether this function should be a member function of the class or a stand alone function.
You are not calling your member functions correctly. print can only be called on an object of type Pojazdy, so you need to do something like:
Pojazdy** poj;
int size{ 0 }, index{ 0 };
Pojazdy x; // Creates an object of Pojazdy called z
x.print(poj,size); // Calls the print method on x
Alternatively, if you don't want to have to declare an object, you could make the method static and just call it on the class.
In the .h file:
static void print(Pojazdy** pojazdy, int size);
And then in main:
Pojazdy** poj;
int size{ 0 }, index{ 0 };
Pojazdy::print(poj, size); // Calls the print method on the class
You put your function prototypes in the wrong place. They should be after the class decalration.
class Pojazdy
{
...
};
void print(Pojazdy** pojazdy, int size);
void wyrejestruj(Pojazdy**& pojazdy, int& size);
etc.
print is not a member of the Pojazdy class, so it's wrong to put the prototype inside the Pojazdy class declaration.

I'm freeing memory twice - C++

I have done this program where I check if my 'date' class is correct. The problem is that when I run my test program, it returned my the following error:
Error in `./bin/test': double free or corruption (fasttop): 0x00000000019c07c0 *
The job of this class is read and store a 'date'(a year) and a few events (allocated in a string array). For example, a object of this class would be: 1998 EVENT1 EVENT2 EVENT3.
Operator >> reads the next format:1908#Fantasmagorie#The Taming of the Shrew#The Thieving Hand#The Assassination of the Duke of Guise#A Visit to the Seaside
Well, my problem is that I'm deleting some pointer twice or freeing some memmory twice, I have tried a lot of things but I don't know how to fix it (as you can see on my code, I have already tried to set all pointers to 0 when I delete them.):
Date class .h
#ifndef _date_HISTORICA_
#define _date_HISTORICA_
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
class date{
private:
int year;
int eventsNum;
int reserved;
string * str;
void resize(int r);
public:
date();
//date(int a, string *s, int n);
date(const date& d);
~date();
int getAge();
void addEvent(string& s);
friend ostream& operator<<(ostream& os, const date& d);
friend istream& operator>>(istream& is, date& d);
};
#endif
Date Class Code:
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<date.h>
using namespace std;
void date::resize(int r)
{
assert(r>=0);
if(r!=this->reserved)
{
if(r!=0)
{
string * aux = new string[r];
if(this->reserved>0)
{
int min=this->reserved<r?this->reserved:r;
for(int i=0; i<min; i++)
aux[i]=this->str[i];
delete[] this->str;
this->str=NULL;
}
this->str=aux;
this->reserved=r;
if(this->reserved<this->eventsNum)
this->eventsNum=this->reserved;
} else
{
if(this->reserved>0)
{
delete[] this->str;
this->str=NULL;
}
this->year=0;
this->eventsNum=0;
this->reserved=0;
}
}
}
date::date() : year(0), eventsNum(0), reserved(0), str(0){}
date::date(const date& d)
{
this->year=d.year;
this->eventsNum=d.eventsNum;
this->reserved=d.reserved;
this->str=new string[this->reserved];
for(int i=0; i<this->eventsNum; i++)
this->str[i]=d.str[i];
}
date::~date()
{
this->year=0;
this->eventsNum=0;
this->reserved=0;
if(this->str)
delete[] this->str;
this->str=NULL;
}
int date::getAge(){return this->year;}
ostream& operator<<(ostream& os, const date& d)
{
os << d.year;
for(int i=0; i<d.eventsNum; i++)
os << '#' << d.str[i];
os << endl;
return os;
}
void date::addEvent(string& s){
if (this->eventsNum == this->reserved){
if (this->eventsNum==0)
resize(1);
else
resize(2*this->reserved);
}
this->str[eventsNum]=s;
eventsNum++;
}
istream& operator>>(istream& is, date& d)
{
string line; char c;
is >> d.year >> c;
getline(is, line);
int n=1;
for(int i=0; i<line.length(); i++)
if(line[i]=='#')
n++;
d.eventsNum=n;
d.reserved=d.eventsNum;
delete[] d.str;
d.str=NULL;
d.str=new string[n];
stringstream ss(line);
for(int i=0; i<n; i++)
getline(ss, d.str[i], '#');
return is;
}
Test Program Class:
#include<iostream>
#include<fstream>
#include<cronologia.h>
#include<date.h>
using namespace std;
int main(int argc, char * argv[]){
cout << "STATE: IN PROGRESS" << endl;
cout << "TEST: (2)" << endl;
date d;
ifstream f("./data/name.txt");
while(f >> d)
{
cout << d;
}
date d1;
cin >> d1;
d=d1;
cout << d << endl;
}
Example file (wich should be read by date clas):
1900#Sherlock Holmes Baffled#The Enchanted Drawing
1901#Star Theatre#Scrooge, or, Marley's Ghost
1902#A Trip to the Moon
1903#The Great Train Robbery#Life of an American Fireman
1904#The Impossible Voyage
1905#Adventures of Sherlock Holmes; or, Held for Ransom
1906#The Story of the Kelly Gang#Humorous Phases of Funny Faces#Dream of a Rarebit Fiend
1907#Ben Hur#L'Enfant prodigue
1908#Fantasmagorie#The Taming of the Shrew#The Thieving Hand#The Assassination of the Duke of Guise#A Visit to the Seaside
Im so sorry for my English!!! :,(
Since there is no assignment overloading in your code, in the line
d=d1;
All the members of d1 will be copied to a new object d by value. Hence there will be two copies of the object date which have the same reference value in their member str. Those two will eventually get out of scope and both will be destructed. The first one will free the allocated memory while the other will try to free that same reference and that is why you get the error.
You need a copy assignment operator:
void swap(date& other)
{
using std::swap;
swap(year, other.year);
swap(eventsNum, other.eventsNum);
swap(reserved, other.reserved);
swap(str, other.str);
}
date::date(const date& d) : year(other.year), eventsNum(other.eventsNum), reserved(other.reserved), str(new string[other.reserved])
{
for(int i = 0; i < this->eventsNum; i++)
this->str[i] = d.str[i];
}
date& date::operator = (const date& d)
{
swap(*this, d);
return *this;
}
Might also be nice to provide a move constructor..

C++ Function causing app to crash and not working properly

A problem has come up in my application where my PrintAll function will not work correctly and only ultimately crash my application. My app is supposed to read strings from a file and insert them into an array. The problem is it is reading incorrectly and will ultimately crash my app. Here is where I think the problem lies:
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
Complete Example:
/*
* File: MovieStatsProgram.cpp
* Author:
* Date:
* ===============================================================
* This is a console app to test the Movie and MovieList classes.
*
* TODO:
*
* You need to finish the implementation of the loadMovies method
* to create and initialize the MovieList object.
*
* You also need to create three static methods:
*
* PrintAllMoviesMadeInYear - it will print all the movies made in a
* given year once sort in alphabetical order and once sorted by the number
* of votes with the movie with the most number of votes printed first.
*
* PrintAllMoviesWithStartLetter - it will print all the movies started with
* a given letter sorted in alphabetical order
*
* PrintAllTopNMovies - it will display the top N movies based on the number of
* votes
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
class Movie {
public:
Movie();
Movie(string n, int y, int v, double r);
string get_name();
void set_name(string n);
int get_year();
void set_year(int y);
int get_votes();
void set_votes(int v);
double get_rating();
void set_rating(double r);
string PrintMovie();
private:
string name;
int year_made;
int votes;
double rating;
};
Movie::Movie() {
name = "null";
year_made = 0;
votes = 0;
rating = 0.0;
}
Movie::Movie(string n, int y, int v, double r) {
name = n;
year_made = y;
votes = v;
rating = r;
}
string Movie::get_name() {
return name;
}
void Movie::set_name(string n) {
name = n;
}
int Movie::get_year() {
return year_made;
}
void Movie::set_year(int y) {
year_made = y;
}
int Movie::get_votes() {
return votes;
}
void Movie::set_votes(int v) {
votes = v;
}
double Movie::get_rating() {
return rating;
}
void Movie::set_rating(double r) {
rating = r;
}
string Movie::PrintMovie() {
cout << fixed << setprecision(1) << rating << "\t\t" << votes << "\t\t" << "(" <<
year_made << ")" << "\t" << name << endl;
}
class MovieList {
public:
MovieList(int size);
~MovieList();
int Length();
bool IsFull();
void Add(Movie const& m);
string PrintAll();
private:
Movie* movies;
int last_movie_index;
int movies_size;
int movie_count = 0;
};
MovieList::MovieList(int size) {
movies_size = size;
movies = new Movie[movies_size];
last_movie_index = -1;
}
MovieList::~MovieList() {
delete [] movies;
}
int MovieList::Length() {
return last_movie_index;
}
bool MovieList::IsFull() {
return last_movie_index == movies_size;
}
void MovieList::Add(Movie const& m)
{
if (IsFull()) {
cout << "Cannot add movie, list is full" << endl;
return;
}
++last_movie_index;
movies[last_movie_index] = m;
}
string MovieList::PrintAll() {
for (int i = 0; i < last_movie_index; i++) {
movies[last_movie_index].Movie::PrintMovie();
//cout << movies[last_movie_index] << endl;
}
}
void ReadMovieFile(vector<string> &movies);
MovieList* LoadMovies();
enum MovieSortOrder
{
BY_YEAR = 0,
BY_NAME = 1,
BY_VOTES = 2
};
int main()
{
LoadMovies();
MovieList *movies = LoadMovies();
//movies->MovieList::PrintAll();
// // test methods for the Movie and MovieList classes
//PrintAllMoviesMadeInYear(movies, 1984);
//PrintAllMoviesWithStartLetter(movies, 'B');
//PrintAllTopNMovies(movies, 5);
//delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
MovieList ml = MovieList(movies.size());
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
}
void ReadMovieFile(vector<string> &movies)
{
ifstream instream;
instream.open("imdbtop250.txt");
if (instream.fail())
{
cout << "Error opening imdbtop250.txt" << endl;
exit(1);
}
while (!instream.eof())
{
string movie;
getline(instream, movie);
movies.push_back(movie);
}
instream.close();
}
When I use MovieList::PrintAll in the main function, my function just crashes, and when I put it in the LoadMovies function, it will read and add data incorrectly before crashing. The size of the list is 251 and the application will just read the same data 251 times.
You have a two part problem:
1: As Brad S stated, your function returns nothing. This is a no-no.
MovieList* LoadMovies()
{
MovieList ml = MovieList(movies.size());
// Your function returns a pointer to a MovieList, so...
return &ml;
}
So, problem #2 is that you're going to return a pointer to something you created on the stack in your function. When you try to access it outside of your function, you'll run into undefined behavior.
Option 1:
MovieList* ml = new MovieList( movies.size() );
return ml;
You now need to delete ml when you're done w/ it.
Option 2:
Change your function to return a non-pointer... then you don't have the hassle of managing the memory.
EDIT: Try this
int main()
{
// Don't need this
// LoadMovies();
MovieList *movies = LoadMovies();
// Uncommented this
delete movies;
return 0;
}
MovieList* LoadMovies()
{
vector<string> movies;
ReadMovieFile(movies);
// CHANGE
MovieList* ml = new MovieList(movies.size());
// CHANGE
string name;
int year;
double rating;
int votes;
for (int i = 0; i < movies.size(); i++)
{
istringstream input_string(movies[i]);
getline(input_string, name, '\t');
input_string >> year >> rating >> votes;
Movie movie (name, year, votes, rating);
ml.Add(movie);
}
ml.PrintAll();
// CHANGE
return ml;
}
Your MovieList class has a fundamental problem. This comes to light on this line:
MovieList ml = MovieList(movies.size());
Your MovieList class has a member that is a pointer to dynamically allocated memory. Once you have this, you have to manage copying and assignment by creating a user-defined copy constructor and assignment operator.
The easiest fix for this is to use std::vector<Movie> instead of Movie * as a member variable of MovieList. Then copy-assignment comes for free and you don't need to implement further functions.
However, if you can't use std::vector for some reason, the following functions can be added:
class MovieList {
public:
//...
MovieList(const MovieList& m);
MovieList& operator=(MovieList m);
//...
};
#include <algorithm>
//...
// copy constructor
MovieList::MovieList(const MoveList& m) {
movies_size = m.size;
movie_count = m.movie.count;
last_movie_index = m.last_movie_index;
movies = new Movie[movies_size];
for (int i = 0; i < movies_size; ++i)
movies[i] = m.movies[i];
}
//...
// assignment operator
MovieList& MovieList::operator=(MoveList m) {
std::swap(m.movie_size, movie_size);
std::swap(m.last_movie_index, last_movie_index);
std::swap(m.movies, movies);
std::swap(m.movie_count, moviE_count);
return *this;
}
The easiest way to describe this to you is not to describe what these do. The best thing for you is to use your debugger and put a breakpoint in any of these functions and step through the code. When you hit the line I mentioned above, you will more than likely see that the copy constructor function is called -- then you can see it in action as to what it is doing.
The assignment operator is the function that's called when you assign an existing MovieList to another MovieList. It's implemented via the copy/swap idiom. This relies on a working copy constructor (provided above), and a destructor (which you already provided in your code). It works by creating a temporary MovieList, and swapping out the internals of the current MovieList with the temporary MovieList. There are many threads on SO as to how this works.
As to the reason why you need these functions above is that without the above functions, the line:
MovieList ml = MovieList(movies.size());
will create two MovieList objects, one temporary and one non-temporary, however the movies pointer for both will be pointing to the same memory. When the temporary is destroyed, the destructor is called, thus deleting the memory pointed to by movies. Now you have m1 pointing to memory that has gone up in smoke. Bad news when you try to use m1.
The user-defined copy and assignment functions above properly copy the object so that you get two distinct memory allocations for movies, so that when the destructor is called, the memory deleted will be unique to that object.
Again, all of this would be alleviated if you used std::vector and forego having to write copy ctor/assignment operators.

how do i create an array where each element in the array, of size 10, is pointing to an object, in C++?

for example lets have a class or struct name Employee with two constructors, a default constructor and a constructor with parameters two strings and an int. why doesn't the following code work?
Employee *employees = (employee*) malloc(sizeof(Employee)*10);
let's say we have an array, size 10, of type string for first name, last name, and one of type int for salary. how to initialize the data members of each object class using the constructor with the parameters?
for (int i = 0; i < 10; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
I've been trying to do this for a few days now but wasn't successful. Also, can anyone tell how to do this using c++'s new and delete operator? and also is there a way this can be done using vectors?
Thank you
header file
class employee{
std::string firstname;
std::string lastname;
int salary;
public:
employee(std::string, std::string , int);
employee();
void setFirst(std::string);
void setLast(std::string);
void setSalary(int);
std::string getFirst();
std::string getLast();
int getSalary();
};
employee::employee(std::string x, std::string y, int z)
{
setFirst(x);
setLast(y);
setSalary(z);
}
void employee::setFirst(std::string x)
{
firstname = x;
}
void employee::setLast(std::string y)
{
lastname = y;
}
void employee::setSalary(int z)
{
salary = z > 0 ? z : 0;
}
std::string employee::getFirst()
{
return firstname;
}
std::string employee::getLast()
{
return lastname;
}
int employee::getSalary()
{
return salary;
}
.cpp file
#define MAX 20
using namespace std;
int main(int argc, char* argv[])
{
int n = 1;
cout << "number of employees: ";
cin >> n;
string firstname[MAX];
string lastname[MAX];
double salary[MAX];
float raise[MAX];
for (int i = 0; i < n; i++)
{
cout << "Employee " << i + 1 <<endl;
cout << "-----------\n";
cout << "First Name: ";
cin >> firstname[i];
cout << "Last Name: ";
cin >> lastname[i];
cout << "Monthly Salary: ";
cin >> salary[i];
salary[i] *= 12;
cout <<"Yearly percentage raise (e.g 10% or 0%): ";
scanf("%f%%", &raise[i]);
salary[i] *= (((raise[i])/100.00) + 1);
puts("\n");
}
employee *employees = (employee*) malloc(sizeof(employee)*10);
for (int i = 0; i < n; i++)
{
employees[i] = employee(firstname[i], lastname[i], salary[i]);
}
cout << "TESING USING GET FUNCTIONS" << endl;
cout << "---------------------------\n\n";
for (int i = 0; i < n; i++)
{
cout << "Employee " <<i +1<< endl;
cout <<"-----------\n";
printf("First Name: %s", employees[i].getFirst().c_str());
printf("\nLast Name: %s",employees[i].getLast().c_str());
printf("\nYearly Salary: %d\n\n", employees[i].getSalary());
}
}
If you have an array of Employee instances and Employee is not POD (http://en.wikipedia.org/wiki/POD) you need to allocate memory from the stack using the operator new:
Employee* employees = new Employee[10];
And for having this working:
for (int i = 0; i < 10; i++)
{
employees[i] = Employee(firstname[i], lastname[i], age[i]);
}
you need to implement the operator= in your Employee class:
Employee& operator=(const Employee& src)
{
_firstname = src._firstname;
_lastname = src._lastname;
_age = src._age;
return *this;
}
If this looks like your Employee class:
class Employee
{
std::string first_name;
std::string last_name;
// other members and functions ...
};
Then using malloc() to create 10 of these is a complete and utter failure. The reason why is that yes, you allocated memory using malloc(), but that's all you did. You didn't construct 10 Employee objects. Those std::string members need to be constructed, not merely have memory allocated. So with that call to malloc() you have 10 fake Employees that were "created", and as soon as you attempt to do anything with one of them, then boom goes your program.
Do research on POD and non-POD types. You cannot treat non-POD types (as the class above is non-POD) as you would a POD type. For a non-POD type, the instance must be "officially" constructed, (the constructor must be invoked).
On the other hand, malloc() knows nothing concerning C++ and what is required to create an object correctly via construction. All malloc (and calloc, and realloc) knows is to allocate bytes and return a pointer to the allocated space.
Use a vector instead, it's resizable, it's easier to manage, and as Grady stated in his comment, it's also generally not good practice to use malloc in C++ code (although it's possible). Maybe do something that looks like this:
#include <vector>
...
int size = 10;
std::vector<Employee *> employees;
for(int i = 0; i < size; i++)
{
//as far as pulling in your data, that depends on where it's coming from
Employee *temp = new Employee(...);
employees.push_back(temp);
}
I'm rusty on my C++ but this should work.
Try this way:
#include <iostream>
class Employee
{
std::string m_firstname;
std::string m_lastname;
int m_age;
public:
Employee()
{
m_firstname=m_lastname="";
m_age=0;
}
void setFirstName(std::string firstname)
{
m_firstname=firstname;
}
void setLastName(std::string lastname)
{
m_lastname=lastname;
}
void setAge(int age)
{
m_age=age;
}
void displayEmp()
{
std::cout<<m_firstname;
std::cout<<m_lastname;
std::cout<<m_age;
}
};
int main()
{
std::string fname;
std::string lname;
int age;
Employee *employee = new Employee[10];
Employee *employeeptr=employee;
for(int i=0;i<10;i++)
{
std::cin>>fname;
std::cin>>lname;
std::cin>>age;
employeeptr->setFirstName(fname);
employeeptr->setLastName(lname);
employeeptr->setAge(age);
employeeptr++;
}
employeeptr=employee;
for(int i=0;i<10;i++)
{
employeeptr->displayEmp();
employeeptr++;
}
delete []employee;
return 0;
}

cannot swap objects in an array in C++

i am new to C++ and stuck in the swap stuff
the code below is a program of sort employee names in alphbetical order and print out the orginal one and sorted one ,but the
swap method doesn't work
the two output of printEmployees is excatly the same, can anyone help me? thx
#include <iostream>
#include <string>
#include <iomanip>
#include <algorithm>
using namespace std;
class employee
{
/* Employee class to contain employee data
*/
private:
string surname;
double hourlyRate;
int empNumber;
public:
employee() {
hourlyRate = -1;
empNumber = -1;
surname = "";
}
employee(const employee &other) :
surname(other.surname),
hourlyRate(other.hourlyRate),
empNumber(other.empNumber){}
void setEmployee(const string &name, double rate,int num);
string getSurname() const;
void printEmployee() const;
employee& operator = (const employee &other)
{employee temp(other);
return *this;}};
void employee::setEmployee(const string &name, double rate, int num) {
surname = name;
hourlyRate = rate;
empNumber = num;
}
string employee::getSurname() const { return surname; }
void employee::printEmployee() const {
cout << fixed;
cout << setw(20) << surname << setw(4) << empNumber << " " << hourlyRate << "\n";
}
void printEmployees(employee employees[], int number)
{
int i;
for (i=0; i<number; i++) { employees[i].printEmployee(); }
cout << "\n";
}
void swap(employee employees[], int a, int b)
{
employee temp(employees[a]);
employees[a] = employees[b];
employees[b] = temp;
}
void sortEmployees(employee employees[], int number)
{
/* use selection sort to order employees,
in employee
name order
*/
int inner, outer, max;
for (outer=number-1; outer>0; outer--)
{
// run though array number of times
max = 0;
for (inner=1;
inner<=outer; inner++)
{
// find alphabeticaly largest surname in section of array
if (employees
[inner].getSurname() < employees[max].getSurname())
max = inner;
}
if (max != outer)
{
//
swap largest with last element looked at in array
swap(employees, max, outer);
}
}
}
int main()
{
employee employees[5];
employees[0].setEmployee("Stone", 35.75, 053);
employees[1].setEmployee
("Rubble", 12, 163);
employees[2].setEmployee("Flintstone", 15.75, 97);
employees[3].setEmployee("Pebble", 10.25, 104);
employees[4].setEmployee("Rockwall", 22.75, 15);
printEmployees(employees, 5);
sortEmployees(employees,5);
printEmployees(employees, 5);
return 0;
}
This code is broken:
employee& operator = (const employee &other)
{employee temp(other);
return *this;}
It should be something like:
employee& operator= (const employee &other)
{
surname = other.surname;
hourlyRate = other.hourlyRate;
empNumber = other.empNumber;
return *this;
}
As told by others, fixing your assignment operator will solve the problem.
I see that you tried to implement operator= in terms of copy constructor but missed to do a swap. You can try the below approach if you want to avoid code duplication in your copy constructor and assignment operator.
employee& operator=(const employee& other)
{
employee temp(other);
swap(temp);
return *this;
}
void swap(employee& other)
{
std::swap(surname, other.surname);
std::swap(hourlyRate, other.hourlyRate);
std::swap(empNumber, other.empNumber);
}