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);
}

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.

#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
};

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.

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.

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 article has been dead for over six months. Start a new discussion instead.