vector push_back not working in class object - c++

I am making an hierarchy of sorts and am having trouble adding an element to a vector. I simplified the code and still cannot add an element to the vector as expected. The hierarchy looks like:
Pdb > Chain > strings
Pdb and Chain are class names and strings is the name of a vector belonging to Chain. I cannot push_back to add a string to strings. You may get a better idea looking at my code:
Chain Class:
class Chain {
string chain_id;
vector<string> strings;
public:
Chain(string id_) { chain_id = id_; }
vector<string> GetStrings() { return strings; }
void AddString(string s) {
cout << "Size of strings BEFORE push_back in AddString: " << strings.size() << endl;
strings.push_back(s);
cout << "Size of strings AFTER push_back in AddString: " << strings.size() << endl;
}
string GetChainId() { return chain_id; }
};
Pdb class:
class Pdb {
string pdb_id;
vector<Chain> chains;
public:
Pdb(string id_) { pdb_id = id_; }
vector<Chain> GetChains() { return chains; }
void AddChain(Chain c) { chains.push_back(c); }
string GetPdbId() { return pdb_id; }
};
main:
int main () {
vector<Pdb> pdbs;
pdbs.push_back(Pdb("1ubq"));
cout << "\n\t1. " << pdbs[0].GetPdbId() << endl;
pdbs[0].AddChain(Chain("A"));
cout << "\n\t2. " << pdbs[0].GetChains()[0].GetChainId() << endl;
pdbs[0].GetChains()[0].AddString("Whateva");
cout << "\n\t3. Size of strings after AddString in main: " << pdbs[0].GetChains()[0].GetStrings().size() << endl;
return 0;
}
This outputs:
1. 1ubq
2. A
Size of strings BEFORE push_back in AddString: 0
Size of strings AFTER push_back in AddString: 1
3. Size of strings after AddString in main: 0
As you can see the AddString function is adding an element to stings within the AddString function itself but when I GetStrings back in main, after executing AddString, strings is empty. I do not understand why this is happening. Any help would be much appreciated.

The problem is that you return a copy of the member, not the member itself:
vector<Chain> GetChains()
should be
vector<Chain>& GetChains()
for this to work.
I must note that you're heavily breaking the single responsibility principle. You're operating on members directly, which can't be a good idea. Consider replacing:
pdbs[0].GetChains()[0].AddString("Whateva");
with something like
pdbs[0].AddStringToChain(0,"Whateva");

Related

Add an element to a vector inside a struct, from within another struct

This is most probably trivial and I'm confusing struct allocation and pointers somehow, I apologize for this. I have read answers to similar questions but it didn't help. The code is, as always, way more complicted, this is a reduction from 3000+ lines of code to the gist.
The output I expected was
prep 1
main 1
Instead, I get
prep 1
main 0
This is the code:
#include <iostream>
#include <vector>
using namespace std;
struct Entry
{
vector<int> list;
};
struct Registry
{
vector<Entry> entries;
void prep()
{
Entry* entry = new Entry();
entries.push_back(*entry);
entry->list.push_back(0);
cout << "prep " << entry->list.size() << "\n";
}
};
int main()
{
Registry registry;
registry.prep();
cout << "main " << registry.entries[0].list.size() << "\n";
return 1;
}
You don't store pointers in your vector<Entry> so you should not use new. Instead add a default constructed Entry using emplace_back.
A C++17 approach:
void prep()
{
Entry& entry = entries.emplace_back(); // returns a ref the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
Prior to C++17:
void prep()
{
entries.emplace_back(); // does NOT return a ref the added element
Entry& entry = entries.back(); // obtain a ref to the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
If you do want to create and maniplate your Entry before adding it to entries, you can do that too and then std::move it into entries.
void prep()
{
Entry entry;
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
entries.push_back(std::move(entry)); // moving is a lot cheaper than copying
}
The problem is the order of the prep() function. If you change to push an element into the Element object, and then push it tho the entries vector, the behavior will be the expected.
void prep()
{
Entry* entry = new Entry();
entry->list.push_back(0);
entries.push_back(*entry);
cout << "prep " << entry->list.size() << "\n";
}
This is happening, because you uses a copy in the entries list.
It is also possible to store the pointer of the object therefore you can edit the actual instance after you pushed to the entries vector.
Edit:
As Ted mentioned, there is a memory leak, because the entry created with the new operator never deleted. Another approach could be to use smart pointers (however, in this small example it seems overkill, just use reference)
void prep()
{
std::unique_ptr<Entry> entry = std::make_unique<Entry>();
entry->list.push_back(0);
entries.push_back(*entry.get()); // get the pointer behind unique_ptr, then dereference it
cout << "prep " << entry->list.size() << "\n";
} // unique_ptr freed when gets out of scope
You need to change the implementation of prep():
void prep()
{
Entry entry;
entry.list.push_back(0);
entries.emplace_back(entry);
cout << "prep " << entries.back().list.size() << "\n";
}
There is no need to allocate a Entry on the heap just to make a copy of it.

C++ Can't figure out output for a class that holds player information. It outputs garbage

I've been pulling my hair out trying to figure out this program. The class has to hold 3 player's info and output their info. My output function is not outputting from my set/get functions. Also, if I output the array indexes the program crashes (that's the array indexes are commented out in the Output function).
edit: I'll just show one profile to keep the code smaller
Any help is appreciated.
#include <cstdlib>
#include <iostream>
using namespace std;
class PlayerProfile
{
public:
void output();
void setName1(string newName1); //player's name
void setPass1(string newPass1); //player's password
void setExp1(int newExp1); //player's experience
void setInv1(string newInv1[]); //player's inventory
void setPos1(int newX1, int newY1); //player's position
string getName1();
string getPass1();
int getExp1();
string getInv1();
int getPos1();
private:
string name1;
string pass1;
int exp1;
string inv1[];
int x1;
int y1;
};
int main(int argc, char *argv[])
{
PlayerProfile player;
cout << "This program generates three player objects and displays them." << endl;
cout << endl;
player.output();
system("PAUSE");
return EXIT_SUCCESS;
}
void PlayerProfile::setName1(string newName1)
{
newName1 = "Nematocyst";
name1 = newName1;
}
void PlayerProfile::setPass1(string newPass1)
{
newPass1 = "obfuscator";
pass1 = newPass1;
}
void PlayerProfile::setExp1(int newExp1)
{
newExp1 = 1098;
exp1 = newExp1;
}
void PlayerProfile::setInv1(string newInv1[])
{
newInv1[0] = "sword";
newInv1[1] = "shield";
newInv1[2] = "food";
newInv1[3] = "potion";
inv1[0] = newInv1[0];
inv1[1] = newInv1[1];
inv1[2] = newInv1[2];
inv1[3] = newInv1[3];
}
void PlayerProfile::setPos1(int newX1, int newY1)
{
newX1 = 55689;
x1 = newX1;
newY1 = 76453;
y1 = newY1;
}
string PlayerProfile::getName1()
{
return name1;
}
string PlayerProfile::getPass1()
{
return pass1;
}
int PlayerProfile::getExp1()
{
return exp1;
}
string PlayerProfile::getInv1()
{
return inv1[0], inv1[1], inv1[2], inv1[3];
}
int PlayerProfile::getPos1()
{
return x1, y1;
}
void PlayerProfile::output()
{
cout << "Player Info - " << endl;
cout << "Name: " << name1 << endl;
cout << "Password: " << pass1 << endl;
cout << "Experience: " << exp1 << endl;
cout << "Position: " << x1 << ", " << y1 << endl;
cout << "Inventory: " << endl;
/*cout << inv1[0] << endl;
cout << inv1[1] << endl;
cout << inv1[2] << endl;
cout << inv1[3] << endl; */
}
This is the output that I am getting:
This program generates three player objects and displays them.
Player Info -
Name:
Password:
Experience: -2
Position: 3353072, 1970319841
Inventory:
Press any key to continue . . .
I'm sorry if I sound like an idiot, this is the first time I have programmed with classes and I am very confused.
First:
You do not have a constructor declared or defined in your class so when you compile, the compiler provides you with a default constructor.
The line
PlayerProfile player;
calls the default constructor provided by the compiler. This default constructor only allocates memory for your class member variables, but does not set their values. This is why name1, pass1, exp1, x1, y1 are not outputting what you expect.
Second:
C++ will not call get or set functions for you, and I think you are misunderstanding how c++ functions work.
this
void PlayerProfile::setName1(string newName1)
{
name1 = newName1;
}
is a function definition. You do not need to assign newName1 inside the function. It's value is passed to the function when a line like
setName1("Nematocyst");
is executed.
If you write a constructor, you can use it to call your set functions, and pass them the values you want to set member variables to.
If you do not want to write a constructor, you can call class functions/methods from main with:
player.setName1("Nematocyst");
Third:
Your program crashes because you are not using arrays properly. Here is a tutorial on how to declare an array and access it's contents.
Generally, I think you are trying to run before you know how to walk. Try not to get frustrated. Learn how arrays work, how functions work, and then how classes work. I hope this is not your homework assignment!

Are structure members of structure passed by reference, passed ONLY by value?

My module tries to do things along the lines of the following program: sub-functions try to modify a structure's elements and give it back to the function to whom the structure is passed by reference.
#include <iostream>
#include <vector>
using namespace std;
struct a
{
int val1;
vector<int> vec1;
};
struct a* foo();
void anotherfunc(struct a &input);
int main()
{
struct a *foo_out;
foo_out = foo();
cout<< "Foo out int val: "<< foo_out->val1<<"\n";
cout<< "Foo out vector size: "<< foo_out->vec1.size()<< "\n";
cout<< "Foo out vector value1: "<< foo_out->vec1.at(0)<< "\n";
cout<< "Foo out vector value2: "<< foo_out->vec1.at(1)<< "\n";
return 0;
}
struct a *foo()
{
struct a input;
input.val1=729;
anotherfunc(input);
return &input;
}
void anotherfunc(struct a &input)
{
input.vec1.push_back(100);
input.vec1.push_back(1000);
input.vec1.push_back(1024);
input.vec1.push_back(3452);
cout<< "Anotherfunc():input vector value1: "<< input.vec1.at(0)<< "\n";
cout<< "Anotherfunc():input vector value2: "<< input.vec1.at(1)<< "\n";
cout<< "Anotherfunc():input int val: "<< input.val1<< "\n";
}
I am expecting the main function to contain the modified integer value in structure (729), and also the vector values (100,10000,1024 and 3452). On the contrary, main has none of these values, and on g++, the program shows a strange behaviour: main() shows that there are 4 elements in the vector inside structure, but when trying to print the values, segfaults.
After some more thought, I assume my question is : "Are structure members of structure passed by reference, passed ONLY by value ?" Should I not expect that vector to have the values set by functions to whom the entire structure is passed by reference? Kindly help.
Vijay
struct a *foo()
{
struct a input;
input.val1=729;
anotherfunc(input);
return &input;
}
You are returning pointer on the local object (it will be destroyed on exit from function), so, there is dangling pointer here and your program has undefined behaviour.
As ForeEveR says, the pointer you are returning is pointing to memory which is no longer guaranteed to contain a valid object. If you want this behavior, allocate input on the heap as follows:
a * foo ()
{
a * input = new input;
input->val1 = 729;
anotherfunc (*input);
return input;
}
Now it is the responsibility of whoever calls foo to free this memory, for example
{
a * foo_out = foo();
// do stuff with foo_out
delete foo_out; foo_out = 0;
}
At some point you will realize that keeping track of who allocated which objects is tedious, when this happens you should look up "smart pointers".
First of all, there is nothing terribly magical about "structures" in C++ — you should treat them like any other type. In particular, you don't need to write the keyword struct everywhere.
So here's your code in more idiomatic C++ (also re-ordered to avoid those wasteful pre-declarations):
#include <iostream>
#include <vector>
using namespace std;
struct a
{
int val1;
vector<int> vec1;
};
void bar(a& input)
{
input.vec1.push_back(100);
input.vec1.push_back(1000);
input.vec1.push_back(1024);
input.vec1.push_back(3452);
cout << "bar():input vector value1: " << input.vec1.at(0) << "\n";
cout << "bar():input vector value2: " << input.vec1.at(1) << "\n";
cout << "bar():input int val: " << input.val1 << "\n";
}
a* foo()
{
a input;
input.val1=729;
bar(input);
return &input;
}
int main()
{
a* foo_out = foo();
cout << "Foo out int val: " << foo_out->val1 << "\n";
cout << "Foo out vector size: " << foo_out->vec1.size() << "\n";
cout << "Foo out vector value1: " << foo_out->vec1.at(0) << "\n";
cout << "Foo out vector value2: " << foo_out->vec1.at(1) << "\n";
}
Now, as others have pointed out, foo() is broken in that it returns a pointer to a local object.
Why all the pointer trickery? If you're worried about copying that vector, then you can dynamically-allocate the a object and use a shared pointer implementation to manage that memory for you:
void bar(shared_ptr<a> input)
{
input->vec1.push_back(100);
input->vec1.push_back(1000);
input->vec1.push_back(1024);
input->vec1.push_back(3452);
cout << "bar():input vector value1: " << input->vec1.at(0) << "\n";
cout << "bar():input vector value2: " << input->vec1.at(1) << "\n";
cout << "bar():input int val: " << input->val1 << "\n";
}
shared_ptr<a> foo()
{
shared_ptr<a> input(new a);
input->val1 = 729;
bar(input);
return input;
}
Otherwise, just pass it around by value.

C++: Why is my vector of structs acting as one struct?

I'm working my way through Accelerated C++ and have decided to mess around with the one of structs that were defined in there. While doing so, I've come across a problem: creating a vector of these structs and modifying the elements in each one seems to modify the elements in all of them.
I realize that this probably means I've initialized all the structs in the vector to a struct at a single memory address, but I used the .push_back() method to insert "dummy" structs in to the vector. I was under the impression that .push_back() pushes a copy of its argument, effectively creating a new struct.
Here is the header for the struct:
#ifndef _STUDENT_INFO__CHAPTER_9_H
#define _STUDENT_INFO__CHAPTER_9_H
#include <string>
#include <iostream>
#include <vector>
class Student_info9{
public:
Student_info9(){homework = new std::vector<double>;};
Student_info9(std::istream& is);
std::string getName() const {return name;};
double getMidterm() const {return midterm;};
double getFinal() const {return final;};
char getPassFail() const {return passFail;};
std::vector<double> *getHw(){return homework;};
void setName(std::string n) {name = n;};
void setMidterm(double m) {midterm = m;};
void setFinal(double f) {final = f;};
private:
std::string name;
double midterm;
double final;
char passFail;
std::vector<double> *homework;
};
#endif /* _STUDENT_INFO__CHAPTER_9_H */
And here is the code that i'm fooling around with (excuse the excessive print statements... the result of some time trying to debug :) ):
vector<Student_info9> did9, didnt9;
bool did_all_hw9(Student_info9& s)
{
vector<double>::const_iterator beginCpy = s.getHw()->begin();
vector<double>::const_iterator endCpy = s.getHw()->end();
return(find(beginCpy, endCpy, 0) == s.getHw()->end());
}
void fill_did_and_didnt9(vector<Student_info9> allRecords)
{
vector<Student_info9>::iterator firstDidnt = partition(allRecords.begin(), allRecords.end(), did_all_hw9);
vector<Student_info9> didcpy(allRecords.begin(), firstDidnt);
did9 = didcpy;
vector<Student_info9> didntcpy(firstDidnt, allRecords.end());
didnt9 = didntcpy;
}
int main(int argc, char** argv) {
vector<Student_info9> students;
Student_info9 record;
for(int i = 0; i < 5; i++)
{
students.push_back(record);
}
for(int i = 0; i < students.size(); i++)
{
students[i].setMidterm(85);
students[i].setFinal(90);
students[i].getHw()->push_back(90);
std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl;
students[i].getHw()->push_back(80);
std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl;
students[i].getHw()->push_back(70);
std::cout << "student[" << i << "]'s homework vector size is " << students[i].getHw()->size() << std::endl;
std::cout << "Just pushed back students[" << i << "]'s homework grades" << std::endl;
if(i == 3)
students[i].getHw()->push_back(0);
}
std::cout << "student[3]'s homework vector size is " << students[3].getHw()->size() << std::endl;
for(vector<double>::const_iterator it = students[3].getHw()->begin(); it != students[3].getHw()->end(); it++)
std::cout << *it << " ";
std::cout << std::endl;
std::cout << "students[3] has " << ( ( find(students[3].getHw()->begin(),students[3].getHw()->end(), 0) != students[3].getHw()->end()) ? "atleast one " : "no " )
<< "homework with a grade of 0" << std::endl;
fill_did_and_didnt9(students);
std::cout << "did9's size is: " << did9.size() << std::endl;
std::cout << "didnt9's size is: " << didnt9.size() << std::endl;
}
As you can see by the print statements, it seems that the homework grades are being added only to one Student_info9 object, copies of which seem to be populating the entire vector. I was under the impression that if you were to use consecutive copies of .push_back() on a single object, it would create copies of that object, each with different memory addresses.
I'm not sure if that's the source of the problem, but hopefully someone could point me in the right direction.
Thanks.
When you push a StudentInfo onto the vector, it is indeed copied, so that's not the problem. The problem is the vector containing the homework grades. Since you only store a pointer to that vector in StudentInfo, only the pointer, not the vector, is copied when you copy a StudentInfo. In other words you have many different StudentInfos that all have a pointer to the same homework vector.
To fix this you should define a copy constructor which takes care of copying the homework vector.
Have you learned about the copy constructor yet? If so, think about what is happening with vector<Student_info9> students on push_back().
Specifically, what happens with this pointer.
std::vector<double> *homework;
The line Student_info9 record; constructs a Student_info9 using the first constructor. This first constructor creates a vector and stores a pointer to it as a member variable. You then proceed to add a copy of this Student_info9 to a vector 5 times. Each copy has a pointer to the same vector.
Your StudentInfo9 class contanis a pointer to a std::vector<double>, which means in the default copy constructor (which will be called when you add a StudentInfo9 object to your vector), the pointer itself is copied. That means all of your StudentInfo9 objects have the same homework vector.
Does that make sense? Please refer to http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/CLASSES-PTRS.html for a more in depth look at pointers and copy constructors.

STL string comparison functor

I have the following functor:
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
It is supposed to be a strict weak ordering, and it's this long (could be one line only) for debug purposes.
I'm using this functor as a comparator functor for a stl::set. Problem being, it only inserts the first element. By adding console output to the comparator function, I learned that it's actually comparing the file name to itself every time.
Other relevant lines are:
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
and
// (FileSet files_;) <- SimulatedDisk private class member
void SimulatedDisk::addFile(SimulatedDiskFile * file) {
files_.insert(file);
positions_calculated_ = false;
}
EDIT: the code that calls .addFile() is:
current_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
current_request++;
}
Where all_requests is a list, and class Request is such that:
class Request {
private:
string file_name_;
int response_code_;
int response_size_;
public:
void setFileName(string file_name);
string getFileName();
void setResponseCode(int response_code);
int getResponseCode();
void setResponseSize(int response_size);
int getResponseSize();
};
I wish I could offer my hypotesis as to what's going on, but I actually have no idea. Thanks in advance for any pointers.
There's nothing wrong with the code you've posted, functionally speaking. Here's a complete test program - I've only filled in the blanks, not changing your code at all.
#include <iostream>
#include <string>
#include <set>
using namespace std;
class SimulatedDiskFile
{
public:
string getFileName() { return name; }
SimulatedDiskFile(const string &n)
: name(n) { }
string name;
};
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
int main()
{
FileSet files;
files.insert(new SimulatedDiskFile("a"));
files.insert(new SimulatedDiskFile("z"));
files.insert(new SimulatedDiskFile("m"));
FileSet::iterator f;
for (f = files.begin(); f != files.end(); f++)
cout << (*f)->name << std::endl;
return 0;
}
I get this output:
z and a: false
a and z: true
z and a: false
m and a: false
m and z: true
z and m: false
a and m: true
m and a: false
a
m
z
Note that the set ends up with all three things stored in it, and your comparison logging shows sensible behaviour.
Edit:
Your bug is in these line:
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
You're taking the address of a local object. Each time around the loop that object is destroyed and the next object is allocated into exactly the same space. So only the final object still exists at the end of the loop and you've added multiple pointers to that same object. Outside the loop, all bets are off because now none of the objects exist.
Either allocate each SimulatedDiskFile with new (like in my test, but then you'll have to figure out when to delete them), or else don't use pointers at all (far easier if it fits the constraints of your problem).
And here is the problem:
SimulatedDiskFile temp_file(current_request->getFileName(),
current_request->getResponseSize());
disk.addFile(&temp_file);
You are adding a pointer to a variable which is immediately destroyed. You need to dynamically create your SDF objects.
urrent_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(...blah..blah..); ====> pointer to local variable is inserted
disk.addFile(&temp_file);
current_request++;
}
temp_file would go out of scope the moment next iteration in while loop. You need to change the insert code. Create SimulatedDiskFile objects on heap and push otherwise if the objects are smaller then store by value in set.
Agree with #Earwicker. All looks good. Have you had a look inside all_requests? Maybe all the filenames are the same in there and everything else is working fine? (just thinking out loud here)