Updating an Object's property in a Vector - c++

I have a vector which contains objects. The objects have a property called first name. I want to update the first name in a property, in order to do that i have to pass the vector which the objects are saved, staff number which uniquely identifies each object and finally the new name taken from the user input.
My problem is it displays the update name in the loop which i use to set the new name but if i use a second loop or a new loop and iterate through the vector again, the new name isn't saved but the old name is displayed.
Here is what i have done :-
public: void updateFirstName(vector<Administrator> vectorUpdate,string staffNumber,string newName)
{
FileHandler<Administrator> adminTObj;
for(Administrator iter: vectorUpdate)
{
if(iter.getStaffNumber()==staffNumber)
{
iter.setFirstName(newName);
cout<<"Update"<<endl;
cout<<iter.getFirstName()<<endl;
//here it prints the updated name but if i use a different loop
//and iterate through the vector the new name is not saved.
}
}
}
What seems to be the problem here ? Thank you

You pass a vector by value
void updateFirstName(vector<Administrator> vectorUpdate,
string staffNumber,string newName)
so each time you call this function you will copy original vector into it and work on this copied vector inside the function. The result of this is the changes are made to local variable inside function. Instead you want to pass vector by reference:
void updateFirstName( vector<Administrator> &vectorUpdate,
string staffNumber,string newName)
In function body, here
for( Administrator iter: vectorUpdate)
you will experienced the same thing. You want to write:
for( Administrator& iter: vectorUpdate)

Related

Calling mutator from other class to change attribute of type vector<string>

So I have a class making clients, and one of the attributes of those clients is the following:
vector<string> *name_set;
and each string in that vector is the name of another client.
So I'm doing something later on where I want to add a string/name on to the end of the name_set.
//just used to select the first client in the vector of type <Client> later on
int other_client = 0;
// this gets the vector <string> of all the names in a given client's name set
vector<string> new_name_set = client.back().getNameSet();
// this adds the new client name to the name_set made previously
new_name_set.push_back(client[other_client].getFullname());
// now I want to change the name_set of the last client in the client vector using my mutator
members.back().setNameSet(const new_name_set);
The error I get on xcode states only 'Expected expression' with a small arrow under the word 'const'
my mutator, for reference is:
void Clients::setNameSet(const vector<string> nameSet){
*name_set = nameSet;
}
This:
members.back().setNameSet(const new_name_set);
Should be:
members.back().setNameSet(new_name_set);

Creating multiple class objects with the same name? c++

I'm making an application that is querying a MySQL database.
I want the results of this to be stored in a map (which has a corresponding pair):
std::map<int, Car*> m_car;
typedef std::pair<int, Car*> m_car_pair;
The car object is made up of 8 parameters, one of which is car_id so firstly I pull the car ID and use it as the key then I want to store the entire car object as the value of the map. (I know this is casing me to be storing the car_id twice but for the moment I don't mind that).
Anyway here's my query code:
void DatabaseController::getAll(QString query_string)
{
// Console log message
std::cout << "Querying Database" << std::endl;
/// Declare SQL query and pass function parameter 'query'
QSqlQuery query(query_string);
// execute the query
query.exec();
int count = 0;
// While results are coming in
while(query.next())
{
// Call car constructor passing all parameters
Car car(query.value(count).toInt(), query.value(count+1).toString(), query.value(count+2).toString(), query.value(count+3).toString(),
query.value(count+4).toInt(), query.value(count+5).toInt(), query.value(count+6).toInt(), query.value(count+7).toString());
if (car.getcarID() != 0)
{
m_car_records.insert(m_car_pair(car.getcarID(), &car));
}
}
std::cout << "Database query finished" << std::endl;
After this I made a quick test function to iterate over the map and pull all of the ID's (map key) and check they were different (i.e. the function worked) and they were.
But that was just a check what I needed was to be able to call the accessory functions from car on the car objects that should be in the map. So I used the same quick test function to iterate over the map and cout << car.toString(); (a simple to string function in the car class):
void DatabaseController::test()
{
m_car_records_iterator = m_car_records.begin();
for(unsigned int i = 0; i < m_car_records.size(); i++)
{
car *test = m_car_records_iterator->second;
std::cout << test->toString() << std::endl;
m_car_records_iterator++;
}
}
This showed the correct number of results however they all were the same i.e. the car object that has been added to every entry in the map is the same (the values of the last record that was found by the query)
My Question is...
Is there any way that using this structure I currently have for my query I can create and add these class objects to my map within the while loop using the same name for each, because of course I can't know how many results are being returned and declare a class object for each one, but as it stands using the same name is just adding the same one every time not actually replacing the values... at least that's what I think is happening??
Any advice or idea would be welcomed (sorry for the long post)
You are experiencing undefined behavior. The reason is that you insert a pointer to a local variable in the map.
In the loop in getAll, when the loop starts over on the next item the car variable is not valid any more.
I suggest you look into std::shared_ptr for the pointers.
This is your problem--
Car car( ... ); // ***Stack allocated
if (car.getcarID() != 0)
{
m_car_records.insert(m_car_pair(car.getcarID(), &car));
}
//But the pointer is what's stored
When the loop iterates, the Car instance is destroyed and the pointer dangles, resulting in undefined behavior. You need
Car* car = new Car( ... );
and then when m_car is no longer needed, you need to iterate through and delete its Car values.

How do I reference successive components (button1, button2, etc.)?

I need to get the number after the button to increment in a for loop. For example, button1 becomes button2, etc. I have tried appending a variable which increments but C++ Builder gives an error saying "Button is not a member of TMain." Is there any way to achieve the end goal or get around this?
You can't construct new identifiers from others at run time. The compiler is correct that Button really isn't a member of your TMain class.
Instead, build the string name of the component you want, and then call your form's FindComponent method to get the component with that name.
for (int i = 1; i <= 2; ++i) {
std::string name = "Button" + IntToStr(i);
TButton* button = dynamic_cast<TButton*>(this->FindComponent(name));
}
That requires that the buttons' Name properties be set accordingly.
Another solution is to forego the component names and put your objects in a proper container, like a vector. For example, you can override the Loaded method (which is where you can be sure all your form's components have been created) and fill a vector there:
void TMain::Loaded() {
TForm::Loaded();
this->m_buttons.push_back(Button1);
this->m_buttons.push_back(Button2);
}
Now when you want to iterate over your buttons, you just iterate over the vector instead:
for (std::vector<TButton*>::const_iterator it = m_buttons.begin();
it != m_buttons.end();
++it) {
// ...
}

creating an array of objects within a function of a program

could someone please tell me what I need to do in order to create an array of objects in a function (other than in the main function).
I will try to explain by making up some sort of example...
Let's say I have a program named TimeScheduler.cpp that implements the class Schedule.h
(and I have the implementation in a separate file Schedule.cpp where we define the methods).
In the declaration file we have declared two constructors
Schedule(); //the default
and
Schedule(int, int, int);//accepts three arguments
to get to the point--let's say in the main program file TimeScheduler.cpp we created our own functions in this program apart from the functions inherited from the class Schedule. so we have our prototypes listed at the top.
/*prototypes*/
void makeSomeTime();
etc.....
we have
main(){
//etc etc...
}
we then define these program functions
void makeSomeTime(){
//process
}
let's say that inside the function makeSomeTime(), we would like to create an array of Schedule objects like this
Schedule ob[]={
summer(5,14, 49),
fall(9,25,50)
};
what do I have to do to the function makeSomeTime() in order for it to allow me to create this array of objects.
The reason I ask is currently i'm having difficulty with my own program in that it WILL allow me to create this array of objects in main()....but NOT in a function like I just gave an example of. The strange thing is it will allow me to create a dynamic array of objects in the function..... like
Schedule *ob = new Schedule[n+1];
ob[2]= Schedule(x,y,z);
Why would it let me assign to a non-dynamic array in main(), but not let me do that in the function?
This is not correct:
Schedule ob[]={
summer(5,14, 49),
fall(9,25,50)
};
You appear to be trying to introduce 3 new names:
ob, which is an array of Scedules
summer, which is a Schedule
fall, which is a Schedule
You can't introduce summer and fall as new names like that. Perhaps this was just a typo, and you meant:
Schedule ob[]={
Schedule(5,14, 49),
Schedule(9,25,50)
};
...which is perfectly fine, and can exist in a function such as:
void make_schedule()
{
Schedule ob[]={
Schedule(5,14, 49),
Schedule(9,25,50)
};
}
But now you have another problem -- your make_schedule function returns void. The Schedule array you created in make_schedule is created and then just thrown away. If you want to return an array from a functtion, the best thing to do is to use a vector, and return that:
std::vector<Schedule> make_schedule()
{
Schedule ob[]={
Schedule(5,14, 49),
Schedule(9,25,50)
};
const size_t num_obs = sizeof(ob)/sizeof(ob[0]);
std::vector<Schedule> ret;
std::copy( &ob[0], &ob[num_obs], std::back_inserter(ret));
return ret;
}
A poorer alternative is to use dynamic allocation to allocate your array, and return a pointer to the first element. In this case, when using new [] it's important to note that you can only use the default constructor.
I decided that instead of using a vector, I could use an unordered_map. I didn't realize that when you 'name' an object in c++, you aren't really giving it a name...it is simply used as a sort of temporary reference. if you want to use names you are better off using a name as a sort of key value in a set. like:
string foodname;
foodname = "cake";
[foodname, 10.95]
foodname = "bread";
[foodname, 5.75]
I found help with unordered_map on http://msdn.microsoft.com/en-us/library/bb981993.aspx

storing to a map inside a function

I'm trying to write a function that will input information into a map from a text file. My main code goes as follows:
int main(){
typedef map<int,student*> record;
record allstudents;
fileinput("inputtest.txt",allstudents);
//rest of code....
}
where the function 'fileinput' is defined as:
void fileinput(string datafile, record map){
fstream file1(datafile);
if(!file1.good()){
//error code
}
//Pulls information from file
student* S1= new physics(name,ID); //creates a new pointer
//(*S1).printinfo(); //Can print info if required for de-bug
map[ID]=S1; //store to map
entries++; //counts entries read in
}
cout<<"Import complete. "<<entries<<" new students entered."<<endl;
}
When I run this piece of code from a test file, it will read in the data and output it fine if I uncomment (*S1).printinfo(); and will correctly count the number of students that have been read in. However when I come back to my main function and output what is now stored in allstudents there appears to be nothing there?
Why is this occurring and does anybody know the way around this problem? I've cut a lot of code out to try and make it easier to read but if you need to see the rest I can always edit this.
Thanks.
This is because you are passing in map by value. Change the signature of the function to
void fileinput(string datafile, record &map)
Short explanation: when you pass by value, a copy of the argument (map) is made. Inside your function you perform modifications to that copy, but these modifications are lost when the function returns and the copy goes out of scope. They do not automatically propagate back to the "source" object.
For a detailed explanation, see Pass by Reference / Value in C++.
You are passing the map by value, so the function makes it's own copy and your original remains unchanged. Try passing by reference:
void fileinput(string datafile, record& map) { ... }
^ reference!