0

I'm having a bit of a problem with function style cast with classes.

When I exit the function I expect an instance of Database to be returned. This instance would then be copied into the db declared in main. I've writtien a copy constructor and it works fine (tested by ordinary initialization) but what I can't seem to copy the data over.

// main
Database const db =	makeDb();

// makeDb()
Database makeDb()
{
	int const size = 100;
	char file[size];
	
	cout << "Enter a file name <press ENTER to use the default name>: ";
	cin.getline( file, size );

//	Database db(file);

//	db.fillDatabase();
//	db.printDatabase();

	return Database(file);
}
2
Contributors
7
Replies
8
Views
10 Years
Discussion Span
Last Post by Ancient Dragon
0

erg i take it back. The problem i'm actually having is with trying to return something by a method called 'return value optimization.' I can't seem to create a copy of the db in the function to the one in in main.

0
#include <iostream>
#include <cstring>
#include <fstream>

#include "state.h"
#include "database.h"

using std::cout;
using std::cin;
using std::ifstream;

class Format
{
public:
	Format(char * string);
	~Format() { delete [] it; }	
	char * getString() { return it; }
	void fixString();
	void upperCase();
	void print() { cout << it << '\n'; }
private:
	char * it;
	int length;
};

Database makeDb();
//////////////////////////  program start  ///////////////////////////////////////
int main(void)
{
	const Database db = makeDb();

	int const size = 100;
	char stateName[size];

	cout << "\nEnter a state name: ";
	cin.getline(stateName, size);

	Format string(stateName);

	string.fixString();
//	string.print();
	const State foundState = db.getState( string.getString() );

	return 0;
}

int State::findState(char * stateName, State & foundState)
{
	if ( strcmp( stateName, name ) == 0 )
	{
		foundState.name = new char[strlen(name) + 1];
		strcpy(foundState.name, name);

		foundState.year = year;

		foundState.cap = new char[strlen(cap) + 1];
		strcpy(foundState.cap, cap);

		foundState.popRank = popRank;

		return 1;
	}
	else
		return 0;
}

State Database::getState(char * stateName) const
{
	State foundState;

	for (int cnt = 0, found = 0; cnt < count && !found; cnt++)
		found = list[cnt].findState( stateName, foundState );
	
	if ( found )
		cout << stateName << " was found!\n";
	else
		cout << stateName << " is not in the database!\n";

	return foundState;
}

Format::Format(char * string)
{
	length = strlen(string) + 1;
	it = new char[length]; 
	strcpy( it, string ); 
}

void Format::fixString()
{
	// capitalize the first letter of the sentence
	it[0] = toupper( it[0] );	

	for (int cnt = 1; cnt < length; cnt++)
		if ( isalpha( it[cnt] ) )
			it[cnt] = tolower( it[cnt] );	// set to lower case
		else if ( it[cnt] == ' ' )
		{
			++cnt;							// move to the beginning of the next word
			it[cnt] = toupper( it[cnt] );	// capitalize
		}
}

void Format::upperCase()
{
	for (int cnt = 0; cnt < length; cnt++)
		if ( isalpha( it[cnt] ) )
			it[cnt] = toupper( it[cnt] );
}

Database makeDb()
{
	int const size = 100;
	char file[size];
	
	cout << "Enter a file name <press ENTER to use the default name>: ";
	cin.getline( file, size );

	Database db(file);

	db.fillDatabase();
	db.printDatabase();

	return db;
}

//////////////////////  Database functions  ////////////////////////////////
// Constructor
Database::Database(char * file)
{
	cout << "Now in the Database constructor" << '\n';

	if ( !file[0] )
		strcpy( file, "states.txt" );
		
	// open input file and check for open success
	if ( ifstream inputFile(file) )
	{
		// allocate memory for Database struct and check for success
		// allocate memory for filename field and initializes with filename
		if ( filename = new char[strlen( file ) + 1] )
			strcpy( filename, file );
		else
			cout << "Not enough memory!" << '\n';
		
		// initialize count field
		count = 5;
		
		// initialize list field by allocating memory for array of 50 states 
		// and check for success
		if ( list = new State[count] ) {}			
		else
			cout << "Not enough memory!" << '\n';

		// close input file
		inputFile.close();
	}
	else
	{
		cout << "File not found!" << '\n';
		exit(0);
	}
}

Database::Database(const Database & arg)
{
	cout << "Now in the copy constructor\n";

	if ( filename = new char[strlen( arg.filename ) + 1] )
		strcpy( filename, arg.filename );
	else
		cout << "Not enough memory!\n";
	
	count = arg.count;

	if ( list = new State[count])
		for ( int cnt = 0; cnt < count; cnt++)
			insertDatabase( cnt, arg.list[cnt] );
	else
		cout << "Not enough memory!\n";
}

Database::~Database()
{
	cout << "Now in the database destructor\n";
	delete [] list;
	delete [] filename;
}
//fillDatabase - reads info from file and stores in array of State structs
//input: pointer to Database struct
//return: nothing
void Database::fillDatabase ()
{
	char name[80];	// temp variables
	int year;
	char cap[80];	// input data
	int popRank;
	int index = 0;	// index into array of State structs
	
	State tempState;
	char array[100]; // temporary storage for file input

	// open file from filename field of db
	// don't need to check for file open success because initDatabase already checked
	ifstream inputFile( filename );
	
	// loop through all the states
	for ( int cnt = 0; cnt < count; cnt++ )
	{
	    // read and parse one line of file into 4 input data fields
		if ( !inputFile.eof() )
		{
			inputFile.getline( array, 100 );

			if ( sscanf( array, "%[^,], %d, %[^,], %d",	name, &year, cap, 
				&popRank ) == 4 )
			{
				// if tempState is created successfully from the 4 input data
				tempState.initState(name, year, cap, popRank);
				insertDatabase (index, tempState);
			}
			else
			{
				cout << "Error with file!" << '\n';
				return;
			}
			index++;
		}
	}
 
 	// close file
 	inputFile.close();
}

void Database::insertDatabase (int index, State const & tempState)
{
	State * pCurrent = list + index; 
	pCurrent->copyState( tempState ); 
}

//printDatabase - print data of state array
//input: pointer to Database struct
//return: nothing
void Database::printDatabase (bool flag) const
{
	cout << " State name      Year     Capital      Pop. rank\n";
	cout << "------------------------------------------------\n";

	if ( flag == true )
		for (int i = 0; i < count; i++)
			list[i].printState();
	else
		cout << "No data to display!" << '\n';
		
	return;
}

State::State( const State & arg )
{
	cout << "Now in the state copy constructor\n";
	name = new char[strlen(arg.name) + 1];
	strcpy(name, arg.name);

	year = arg.year;

	cap = new char[strlen(arg.cap) + 1];
	strcpy(cap, arg.cap);

	popRank = arg.popRank;
}

State::~State()
{
	cout << "Now in the state destructor\n";
	
	cout << "deleted " << name << ',' << cap << '\n';
	delete [] name;
	delete [] cap;
}

////////////////////////  State functions  //////////////////////////////
void State::initState(char * tempName, int tempYear, char * tempCap, int tempPopRank)
{
	char * stateName;
	char * capital;
   // if memory allocation is successful, store name
	if ( stateName = new char[strlen( tempName ) + 1 ] )
	{
		strcpy( stateName, tempName );
  		name = stateName;
	}
	else
	   cout << "Not enough memory!" << '\n';
   
	// store year
	year = tempYear;
   
	// if memory allocation is successful, store capital
	if ( capital = new char[strlen( tempCap ) + 1 ] )
	{
		strcpy( capital, tempCap );
		cap = capital;
	}
	else
		cout << "Not enough memory!" << '\n';
   
	// store population ranking
	popRank = tempPopRank;
}

//copyState - copies contents between two State structs
//input: pointer to source State struct
//       pointer to destination State struct
//return: nothing
void State::copyState (State const & tempState)
{
	name = new char[strlen(tempState.name) + 1];
	strcpy ( name, tempState.name );

	year = tempState.year;

	cap = new char[strlen(tempState.cap) + 1];
	strcpy( cap, tempState.cap );

	popRank = tempState.popRank;
}

//printState - displays State data
//input: pointer to State struct
//return: nothing
void State::printState ()
{
	cout.setf(ios_base::left);
	cout.width(17);
	cout << name;
	
	cout.setf(ios_base::left);
	cout.width(8);
	cout << year; 

	cout.setf(ios_base::left);
	cout.width(18);
	cout << cap;

	cout.setf(ios_base::left);
	cout.width(2);
	cout << popRank << '\n';	

	return;
}

class State
{
public:
	State() { name = 0; cap = 0; }
	State( const State & arg );
	~State();
	int findState(char * stateName, State & foundState);
	void initState(char * tempName, int tempYear, char * tempCap, int tempPopRank);
	void copyState(State const & tempState);
	void printState();
private:
	char * name;	// state name
	int year;		// year of entry into the union
	char * cap;		// state capital
	int popRank;	// population ranking
};

class Database
{
public:
	Database(char * file = "states.txt");
	Database(const Database & arg);
	~Database();
	State getState(char * stateName) const;
	void deleteDatabase ();
	void fillDatabase ();
	void insertDatabase (int index, State const & tempState);
	void printDatabase (bool flag = true) const;
private:
	State * list;		// array of states
	int count;			// total count of states
	char * filename;	// input filename
};
0

erg i take it back. The problem i'm actually having is with trying to return something by a method called 'return value optimization.' I can't seem to create a copy of the db in the function to the one in in main.

There is no such function in the code you posted. And function names can not contain spaces.

0

In the makeDb() function, I returned the instance back by value. Based on my teacher's lecture last Tuesday, however, that's very wasteful (as you have to invoke ctor/dtor/copy ctor calls) and we're supposed to use return value optimization (RVO).

My original function was what I had posted originally and I could not create the db instance in main from what was returned from makeDb() via RVO. That's what I've been trying to hammer out.

0

Yes your teacher is correct -- returning the db object like you did is very wasteful of system resources and time.

What I would do is pass a reference to an existing db object to makeDb() so that it does not have to return the object.

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.