Variable losing value

Hello, all!
I have a problem where a std::string is being passed to multiple nested methods, and somewhere along the line, it goes from having a value to becoming an empty string.

The chain begins here:

//Create a new group based on the entered name
patients->CreateNewGroup(diag->get_name());

diag->get_name() returns a standard string, and GDB confirms that it is returning the value I enter when I run the program: "Test"

Inside patients->CreateNewGroup(), we have:
void PList::CreateNewGroup(string gc){
PatientGroup g(gc);
groups.push_back(g);
}

groups is of type std::vector<PatientGroup>
GDB confirms that gc contains the value "Test" as expected.

Inside the constructor for PatientGroup, we have:
PatientGroup::PatientGroup(string c){
code=c;
}

code is of type std::string. Here is where we run into problems. GDB shows c as being an empty string, and sure enough, when we allow the program to run, the created PatientGroup object has no value stored in the variable "code", causing issues to pile up down the line.

It seems like this code should be pretty straightforward, but between PList::CreateNewGroup() and PatientGroup::PatientGroup, the string is going from having a value to not having a value.

What on earth is happening? Anyone have any ideas on how to fix it?
If what you've shown is really all there is then it's impossible. So there must be something more to it. We need to see the entire program.
Is code a std::string or a std::string&?

I agree that having more code to look at would be helpful. Please create a minimal program that exhibits the behavior you are seeing.

When you post your code, please use code tags for formatting. Click the Format button that looks like "<>" and paste your code between the generated tags.
You maybe corrupting the heap earlier in the program. Put another way, the empty string may just be a symptom of a bug that occurs much earlier.
@doug4:
The 'code' cannot be a reference, because:
1
2
3
4
PatientGroup::PatientGroup( string c )
{
  code = c;
}

1. One cannot assign to a reference. One has to initialize a reference; one cannot later change where it refers to.

To overcome that, one should initialize the 'code':
1
2
3
4
PatientGroup::PatientGroup( string c )
 : code( c )
{
}

However,
2. You definitely cannot/shouldn't store a non-const reference to a temporary object, like 'c'.

Looking back at the first version:
1
2
3
4
5
PatientGroup::PatientGroup( string c )
 : code()
{
  code = c;
}

The 'code' is indeed an empty string after its initialization and before the assignment. Alas, that should not be the issue here.
Last edited on
@doug4:
The 'code' cannot be a reference, because:


Of course not. What was I thinking?

Thanks for correcting me.
1. One cannot assign to a reference.

To be clear to the readers, we can, and we do it all the time. However it changes the referenced variable. It does not cause the reference to refer to a new variable. The way to think of a reference is that it's a synonym for another (existing) variable.
1
2
3
4
string str1 {"hello"};
string str2 {"there"};
string &ref(str1);    // ref is a synonym for str1.
ref = str2;              // same as saying str1 = str2; 

My bad. Thanks.

My point was on that you have to initialize the reference members and initialization occurs before the body of the constructor.
1
2
3
4
5
6
7
8
9
struct Foo {
  Bar & bar;

  Foo( Bar gaz )
  // error: uninitialized reference
 {
    bar = gaz; // What does foo refer to?
 }
};

is like writing:
1
2
3
4
Bar gaz;

Bar & foo; // error: uninitialized reference
foo = gaz; // What does foo refer to? 



Since initialization occurs before the body of the constructor, the PatientGroup::code is default-initialized in OP's constructor and the code = c; is a mere assigment, change of existing and initialized object.


Overall, I do agree that the OP has not shown all relevant code.
I apologize for not providing enough code. I've written a minimal program that has the same behavior, the source code for which is here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Tests the formation of a new goup using the PList infrastructure

#include <iostream>
#include <string>

//Local includes
#include "plist.h"

using namespace std;

int main(int argc,char *argv[]){
	
	//Create a new Plist
	PList *test=new PList();
	
	cout<<"Enter a group name: ";
	string gn="";
	cin>>gn;
	
	//Create the new group via PList
	test->CreateNewGroup(gn);
	
	//Verify that a new group has been created
	if(test->Groups().size()>=1){
		cout<<"PList::Groups().size() = "<<test->Groups().size()<<endl;
		//What is the name of the created group?
		cout<<"Name of the created group: "<<test->Groups()[0].Code()<<endl;
	}else{
		cout<<"Failed to create new group."<<endl;
	}
	
	return 0;
	
}


test->Groups()[0].Code() should return the value we supplied to cin. Instead it returns an empty string.

Here are the other relevant files:

plist.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//The total set of all patients encoded in a file

#ifndef __PATIENTENCODER__PLIST_H__
#define __PATIENTENCODER__PLIST_H__

//STL includes
#include <string>
#include <vector>

//Local includes
#include "group.h"
#include "patient.h"
#include "suffix.h"

//macros
#define CODE_DOES_NOT_EXIST 0x34E5

class PList{
private:
	
	//Stores patients and groups as unsorted stacks
	//	PatientGroup stores patients as a sorted, code-ordered list
	vector <Patient*> patients;
	vector <PatientGroup> groups;
	//The code generator object
	SuffixGenerator *gen;
	
public:
	
	//Constructors
	PList(void)=default;
	PList(SuffixGenerator*);
	~PList(void)=default;
	
	//Add/Remove
	//These use actual patient pointers and group objects
	void AddPatient(Patient*);
	void AddPatientToGroup(Patient*,PatientGroup&);
	//Same thing using references to patient and group codes
	void AddPatientToGroup(string,string);
	void DeletePatient(string);
	//Creates/deletes new groups
	void CreateNewGroup(string);
	void DeleteGroup(string);
	
	//Accessors -- accessed using a string code
	PatientGroup &Group(string);
	Patient *GetPatient(string);
	vector<Patient*> Patients(void);
	vector<PatientGroup> Groups(void);
	
};

#endif // __PATIENTENCODER__PLIST_H__ 


plist.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//Implementation for Patient lists

#include "plist.h"

using namespace std;

//Constructors
PList::PList(SuffixGenerator *g){
	gen=g;
}

//Add/remove
void PList::AddPatient(Patient *p){
	patients.push_back(p);
	gen->update(p);
}

void PList::AddPatientToGroup(Patient *p,PatientGroup &g){
	g.Add(p);
}

void PList::AddPatientToGroup(string pcode,string gcode){
	Patient *ref=NULL;
	for(vector<Patient*>::iterator it=patients.begin();it!=patients.end();++it){
		if((*it)->Code()==pcode){
			ref=(*it);
			it=patients.end();
			--it;
		}
	}
	if(!ref) throw CODE_DOES_NOT_EXIST;
	for(vector<PatientGroup>::iterator it=groups.begin();it!=groups.end();++it){
		if((*it).Code()==gcode){
			(*it).Add(ref);
		}
	}
}

void PList::DeletePatient(string pc){
	//First we search all the groups to pop this patient out
	for(vector<PatientGroup>::iterator it=groups.begin();it!=groups.end();++it){
		//We can just delete without checking, since PatientGroup removes safely
		(*it).Remove(pc);
	}
	//The patient has been removed from all groups
	//Now we delete the master patient
	Patient *p=NULL;
	vector<Patient*>::iterator ref=patients.end();
	for(vector<Patient*>::iterator it=patients.begin();it!=patients.end();++it){
		if((*it)->Code()==pc){
			p=*it;
			ref=it;
			it=patients.end();
			--it;
		}
	}
	if(p && ref!=patients.end()){
		patients.erase(ref);
		delete p;
	}
}

void PList::CreateNewGroup(string gc){
	PatientGroup g(gc);
	groups.push_back(g);
}

void PList::DeleteGroup(string c){
	for(vector<PatientGroup>::iterator it=groups.begin();it!=groups.end();++it){
		if((*it).Code()==c){
			groups.erase(it);
			it=groups.end();
			--it;
		}
	}
}

/********************END ADD/REMOVE*****************************/

//Accessors
PatientGroup &PList::Group(string c){
	for(int i=0;i<(int)groups.size();i++){
		if(groups[i].Code()==c) return groups[i];
	}
	throw CODE_DOES_NOT_EXIST;
}

Patient *PList::GetPatient(string pc){
	for(vector<Patient*>::iterator it=patients.begin();it != patients.end();++it){
		if((*it)->Code()==pc) return (*it);
	}
	return NULL;
}

vector <PatientGroup> PList::Groups(void){
	return groups;
}

vector<Patient*> PList::Patients(void){
	return patients;
}

/****************************END ACCESSORS*******************/


group.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//Defines an object containing a sorted group of patients

#ifndef __PATIENTENCODER_GROUP_H__
#define __PATIENTENCODER_GROUP_H__

//STL includes
#include <set>
#include <string>

//Local includes
#include "patient.h"

class PatientGroup{
private:
	
	set <Patient*> patients;
	string code;
	
public:
	
	//Constructors
	PatientGroup(void)=default;
	PatientGroup(string);
	PatientGroup(string,set<Patient*>);
	PatientGroup(const PatientGroup&);
	~PatientGroup()=default;
	
	//Accessors
	Patient *operator[](string); //Takes a code string, returns the patient object
	set<Patient*> Patients(void);
	void Add(Patient*);
	void Remove(Patient*);
	void Remove(string);
	size_t Size(void);
	string &Code(void);
	
	//Comparators
	bool operator==(PatientGroup);
	bool operator!=(PatientGroup);

};

#endif // __PATIENTENCODER_GROUP_H__ 


group.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//Implementation file for a patient group

#include "group.h"

using namespace std;

//Constructors
PatientGroup::PatientGroup(string c){
	code=c;
}

PatientGroup::PatientGroup(string c,set<Patient*> h){
	code=c;
	patients=h;
}

//Copy constructor
PatientGroup::PatientGroup(const PatientGroup& h){
	patients=h.patients;
}
/*******************END CONSTRUCTORS****************/

//Accessors
Patient *PatientGroup::operator[](string code){
	for(set<Patient*>::iterator it=patients.begin();it!=patients.end();++it){
		if((*it)->Code()==code) return *it;
	}
	return NULL;
}

set<Patient*> PatientGroup::Patients(void){
	return patients;
}

void PatientGroup::Add(Patient* h){
	patients.insert(h);
}
			
void PatientGroup::Remove(Patient *p){
	set<Patient*>::iterator r=patients.end();
	for(set<Patient*>::iterator it=patients.begin();it!=patients.end();++it){
		if((*it)->operator==(*p)){
			r=it;
			it=patients.end();
			--it;
		}
	}
	if(r!=patients.end()) patients.erase(r);
}

void PatientGroup::Remove(string c){
	
	set<Patient*>::iterator r=patients.end();
	for(set<Patient*>::iterator it=patients.begin();it!=patients.end();++it){
		if((*it)->Code() == c){
			r=it;
			it=patients.end();
			--it;
		}
	}
	
	if(r!=patients.end()) patients.erase(r);
	
}

size_t PatientGroup::Size(void){
	return patients.size();
}

string &PatientGroup::Code(void){
	return code;
}
/********************END ACCESSORS**********************/

//Comparators
bool PatientGroup::operator==(PatientGroup pg){
	if(code!=pg.Code()) return false;
	if(patients.size()!=pg.Size()) return false;
	//We know the two groups are guarenteed to be the same size at this point
	for(set<Patient*>::iterator it1=this->Patients().begin(),it2=pg.Patients().begin();it1!=this->Patients().end() && it2!=pg.Patients().end();++it1,++it2){ //Cycle through all the patients in both groups simultaneously
		if((*it1)->operator!=(*(*it2))) return false;
	}
	return true;
}

bool PatientGroup::operator!=(PatientGroup pg){
	return !this->operator==(pg);
}


It exhibits the same thing as the original program; the string object is losing value somewhere. Help is much appreciated.
patient.h please
patient.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#ifndef __PATIENTENCODER_PATIENT_H__
#define __PATIENTENCODER_PATIENT_H__

//STL includes
#include <cstdlib>
#include <iostream>
#include <string>

//Macros
//Gender
#define peGENDER_FEMALE 'F'
#define peGENDER_MALE 'M'
#define peGENDER_TRANS 'T'
#define peGENDER_DEFAULT peGENDER_FEMALE
//Race
#define peRACE_WHITE 'W'
#define peRACE_BLACK 'B'
#define peRACE_HISPANIC 'H'
#define peRACE_ASIAN 'A'
#define peRACE_BIRACIAL 'I'
#define peRACE_OTHER 'O'
#define peRACE_DEFAULT peRACE_WHITE
//Define others once we verify the time2track categories
//Orientation
#define peORIENTATION_STRAIGHT 'S'
#define peORIENTATION_GAY 'G'
#define peORIENTATION_BI 'B'
#define peORIENTATION_UNKNOWN 'U'
#define peORIENTATION_OTHER 'O'
#define peORIENTATION_DEFAULT peORIENTATION_UNKNOWN
//Define others once we verify the time2track categories

using namespace std;

class Patient{
private:
	
	int age;
	char gender;
	char race;
	char orientation;
	string name;
	string code;
	
public:
	
	//Constructors
	Patient(void);
	Patient(string,string,int,char=peGENDER_DEFAULT,char=peRACE_DEFAULT,char=peORIENTATION_DEFAULT);
	Patient(const Patient&);
	~Patient()=default;
	
	//Accessors
	int &Age(void);
	char &Gender(void);
	char &Race(void);
	char &Orientation(void);
	string &Name(void);
	string &Code(void);
	
	//Operators
	Patient &operator=(Patient&);
	bool operator==(Patient);
	bool operator!=(Patient);
	bool operator<(Patient); //For container sorting
	
	void print(void);
	
};

#endif // __PATIENTENCODER_PATIENT_H__ 
Also, it seems, suffix.h , and probably anything else still missing.
Here's suffix.h and that should be it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//Object to generate suffix codes

#ifndef __PATIENT_ENCODER_SUFFIX_GEN_H__
#define __PATIENT_ENCODER_SUFFIX_GEN_H__

//System/STL includes
#include <cstdlib>
#include <map>
#include <string>
#include <vector>

//local includes
#include "patient.h"

using namespace std;

class SuffixGenerator {
private:
	
	//key is a year, value is another map
	//	2nd map key is an age, value is a suffix code
	map<string,map<string,string> > codes;
	
	//iterates a letter code
	string iterate(string);
	
public:
	//Constructors
	SuffixGenerator(void)=default;
	SuffixGenerator(vector<Patient*>);
	
	//tracking
	void update(Patient*);
	//Next code -> takes a year and an age and returns the next suffix code
	string nextCode(string,string);
	
	//A debug method
	void test(void);
	
};

#endif // __PATIENT_ENCODER_SUFFIX_GEN_H__ 
You have forgot to copy the value of code in PatientGroup's copy constructor.
That solved it! Thank you so much!
Topic archived. No new replies allowed.