C++ Vector become empty in instance class after pushing some data - c++

class Bank {
private:
string bankName;
vector<Account> accounts;
public:
Bank(string name){
bankName = name;
}
Account registerAccount(string name){
Account account(name, rand());
accounts.push_back(account);
return account;
}
void checkMyAccount(Account account){
cout << accounts.size();
cout << bankName;
for(Account acc : accounts){
if(acc.getBankId() == account.getBankId()){
cout << acc.getName();
}
}
}
};
I am new in c++, and do you know why in another method my vector become empty after pushing some data? this is full code https://repl.it/#mufti1/CircularFrontSigns

So the problem is that you have two different bank objects
Bank bank("BCA");
Account customerAccount = cust.requestAccount(bank);
Account requestAccount(Bank bank){
return bank.registerAccount(name);
}
The bank object in requestAccount is a copy of the bank object in main. So you add an account to the copy but not to the original in main.
To solve use a reference
Account requestAccount(Bank& bank){
return bank.registerAccount(name);
}
By using a reference Bank& the bank object is not copied, and your code alters the Bank object in main instead of the local copy.
For some reason beginners often assume that C++ passes objects by reference by default. But this is not the case, if you want a reference you have to ask for it.

Your problem is here:
Account requestAccount(Bank bank) //<--- you are passing by value
{
return bank.registerAccount(name);
}
When you call requestAccount(bank), you create a copy of the original Bank object:
Account customerAccount = cust.requestAccount(bank);
To fix this, change the function to:
Account requestAccount(Bank& bank) { //pass by reference
...
}

The problem is in code you did not show in the post : your requestAccount method takes a Bank object by copy instead of by reference. You should delete the Bank copy constructor (or make it private) to prevent these things from happening again.

Related

Do I need to use a pointer in this situation, when trying to update a variable from a separate class?

So my program is intended to accept input from the user to create an object with several attributes(variables) and those objects are put into vector. I'm having a particular issue with being able to change the quantity of a particular item in question. It remains unchanged regardless of how many times I call the function from main.cpp.
class ClassA {
public:
void SetQuantity(int quantityToGet);
...
private:
int itemQuantity;
...
};
void ClassA::SetQuantity(int quantityToGet) {
itemQuantity = quantityToGet;
}
class ClassB {
public:
ClassB();
void UpdateItemQnty();
int FindItemLoc(string targetItem);
...
private:
vector<ClassB> itemsInVector;
...
};
void ClassB::UpdateItemQnty() {
ClassA currItem;
string targetName;
int newQuantity;
int itemLoc = -1;
cout << "Enter the item name: ";
getline(cin, targetName);
itemLoc = FindItemLoc(targetName);
cout << "Enter the new quantity: ";
cin >> newQuantity;
cin.ignore();
if (itemLoc > -1) {
currItem = itemsInVector.at(itemLoc);
currItem.SetQuantity(newQuantity); // FIXME (???)
}
else {
cout << "Item not found in vector. Nothing modified." << endl;
}
}
I'm not getting any errors and the functions I didn't mention or show definition/declarations for, all work properly. I think I need to use a pointer, but I'm not sure how.
I'll likely delete this after I receive an answer based on the response
Thank You
I can see two strange things in your code:
Your are assigning a ClassA object with ClassB object (above the call of setQuantity). That should give an error, but I guess you made a typo in your post...
when retrieving the data from the list, your are copying it to the local variable currItem! Hence you are only changing a local copy, not the data in the list.
Declaring currItem as a reference would do the trick in this case, but the declaration of a reference object requires an assignment:
ClassA &currItem = itemsInVector.at(itemLoc);
currItem.SetQuantity(newQuantity);
You're simply setting the temporary variable's value. Try this,
itemsInVector[itemLoc].SetQuantity(newQuantity);

Copy constructor with reference counting

I am trying to implement reference counting. Every copy of object should increment the counter for it.
My code looks
class Person{
public:
struct Kids{
Kids(){
count = 2;
boy = "Alex";
girl= " Lisa";
}
int count;
string boy;
string girl;
};
Person( string name , int age){
this -> name = name;
this -> age = age;
}
Person( const Person& a){
one = a.one;
one -> count++;
age = a.age;
name = a.name;
for( int i = 0; i < 5; i++){
family[i] = a.family[i];
}
};
void PrintIt(){
cout << one -> count << endl;
}
private:
Kids *one;
string name;
int age;
Kids family[5];
};
int main(){
Person one("Jogn",50);
//return 0;
Person two(one);
two.PrintIt();
}
And it throws seg fault. I have tried to pass object to copy constructor as a pointer , which resulted in the same output. How can create a copy constructor ,that will point to object via pointers , which will result in possible reference counting?
Have you tried std::shared_ptr, it is available in C++ 11. This template class has the advantages of being well tested and already developed. Here you have a link to the documentation.
Kids *one;
Seems to be uninitialized. When you copy a value to it. this value is also unitialized, since it is private, and i don't see any init code for it. You have to add something like
kids(new Kids())
in Person constructor which is not copy one.
ps. don't forget operator= and destructor.
just make a static variable in private and outside your class initialize it to zero using the scope resolution operator. Then inside your constructor increment it by one. Each time you will make an object its constructor will be called and the static variable will be incremented by one. Then when ever you want you can display that variable where ever you want (again by using scope resolution operator).

Storing a pointer in class

I'm learning C++ and having trouble with pointers.
This simple project consists in a invoice that has a pointer to a customer.
Classes:
class Customer {
string name;
public:
Customer(string name) { this->name = name; };
string getName() { return name; };
void changeName(string name) { this->name = name; };
};
class Invoice {
Customer * customer;
public:
Invoice(Customer *customer) { this->customer = customer; };
Customer getCustomer() { return *customer; };
};
Main:
Customer *customer1 = new Customer("Name 1");
Invoice invoice1(customer1);
cout << invoice1.getCustomer().getName() << endl; //Return:Name 1;
How can I use Customer::changeName(string name) in order to make this work:
(...) changeName("Name 2");
cout << invoice1.getCustomer().getName() << endl; //Return:Name 2;
I don't know what I should use to change the customer's name. Or maybe I'm doing something wrong in the class Invoice.
Why change the name through Invoice?
So I can learn how I can learn how to use the pointer before the project starts getting big.
Later I'm going to have a vector of Invoices and a vector of Customers. Getting the pointer to a Customer from a Invoice or from a vector of Customers should be the same.
Thank you,
Eduardo
Customer getCustomer() { return *customer; };
should be
Customer& getCustomer() { return *customer; };
because in the first case you copy the customer object and so your changes happen in a temporary object that gets thrown away...
in the second you will return a reference to the object you created.
to change name
string newName = "Edu";
invoice1.getCustomer().changeName( newName );
If you want this substantially hardened, i've taken such liberties here. Both Customer and Invoice declarations are significantly updated. Compare them to your existing code. Don't just copy this into your code, as it will definitely break a ton of things. Rather, look at it and see if it makes sense to you:
class Customer
{
string name;
public:
Customer(const string& name) : name(name) {};
const string& getName() const { return name; };
void changeName(const string& name) { this->name = name; };
};
class Invoice
{
const Customer& customer;
public:
Invoice(const Customer& customer) : customer(customer) {};
const Customer& getCustomer() const { return customer; };
};
In general (more often than not, anyway) the only times you should need to pass an object by pointer is if there is a chance the object pointer receiver should accept NULL as a valid value. Otherwise use references or smart pointers. Arrays of object pointers to support polymorphic access not withstanding (and even then, smart pointers ftw), this is generally a good rule to follow.
Significant changes made:
Uses const references unless there is specific need for non-const-access
Classes have initializer lists to ensure best-construction for member vars, and, in fact are required now for Invoice, since the Customer reference memeber must be initialized in an initializer list.
Main
Customer customer1("Name 1");
Invoice invoice1(customer1);
// note: invoice now only allows you to obtain a const-reference
// to the customer of the invoice. As such, you can only fire
// const-members on the returned customer reference.
cout << invoice1.getCustomer().getName() << endl; //Return:Name 1;
// without the const-ness of the getCustomer() member and the reference
// it returns, you would have been able to do this:
//
// invoice.getCustomer.changeName("newname");
//
// As it is written now, you can only change a customer name from
// a non-const customer reference (or pointer), and in doing so,
// *all* invoices for that customer will reflect this change.
customer1.changeName("Name 2");
// note: the invoice was not changed, but the customer it references
// was, and we should see that change now.
cout << invoice1.getCustomer().getName() << endl; //Return:Name 2;
I hope this gives you some ideas on how to restrict and harden your object access later on in your project.
In Invoice, return the pointer to the Customer itself, rather than a copy of its dereferenced value:
Customer* getCustomer() { return customer; };
Then you can change the name like so, and the change will affect the actual Customer object:
invoice1.getCustomer()->changeName("Name2")

What is wrong with this c++ code?

As you can see I am new to C++, but I can't understand why y = new Person() in function foo is wrong. Thanks for your help.
I get the this error:
error: no match for ‘operator=’ in ‘y = (((Person*)operator new(32u)),
(, ))’
UPDATE:
I will accept the answer with the most upvotes by tonight or the one that is more convincing.
The argument between me and my friend is wether the function foo can change the object and propagate the change outside the function like when doing y = Person(), then also brother will change or will it remain intact?
.
CODE:
#include <iostream>
using namespace std;
class Person {
public:
int age;
char name[25];
Person() {
age = 0;
}
};
void foo(Person &y)
{
y = new Person();
}
int main()
{
Person *brother = new Person();
brother->age = 20;
cout << "age = " << brother->age << endl;
foo(*brother);
cout << "age = " << brother->age << endl;
return 0;
}
You probably come from a language were objects can only be created with new. In C++, this is not the case. And unless you really need it, you should not use new. Just create it as a normal variable:
#include <iostream>
#include <string>
class Person
{
public:
unsigned age;
std::string name;
Person(unsigned age, std::string name)
: age(age)
, name(std::move(name)) // move is C++11
{}
};
int main()
{
Person brother(8, "Tim John");
std::cout << "age = " << brother.age << '\n';
// Edit regarding the question in the comments:
brother = Person(16, "John Tim");
std::cout << "age = " << brother.age << '\n';
}
Your problem with the code above is that new returns a Pointer, and you are trying to assign a pointer to a Person, which obviously can't work.
void foo(Person &y)
{
y = new Person();
}
y is a reference, not a pointer. To reassign to y, you'd use
y = Person();
but if you really want to allocate a new person, you'd use
void foo(Person* &y) // reference to pointer to Person
With a reference, you basically say that you modify the value at the calling site.
Note that your current code leak. If you have a bare pointer that you want to manage yourself, you have to delete it first:
void foo (Person*& y)
{
delete y;
y = new Person;
}
But as you see, the code is already becoming messy without knowing your target. It might be more appropriate to delete at the calling site, or to not allocate y at all before calling foo(...).
Also note that using foo (Person* y) instead would not solve the issue of newing at the calling site:
void foo (Person *y)
{
y = new Person();
}
This of course compiles, but modifies only foo's own y variable. The caller will have an unchanged pointer.
Note that you'd better use value types or smart pointers, as it is non-trivial to write exception safe code that manually manages memory.
In function foo the line should be
y = Person();
y is not a pointer.
EDIT: actually, this is the wrong answer (even though you're currently accepted it from Jon). You are not supposed to mix heap and stack, and cause memory leaks like that. The right way to do it is to change members of the object directly. Assignment operator (operator=) will change the members of the object. Because the question is not about mixing heap and stack, but about changing object here's the code that better explains the problem. Note that there's no new here to complicate the issue.
void foo(Person &y)
{
y = Person();
}
int main()
{
Person brother;
brother.age = 20;
...
foo(brother);
...
return 0;
}
After y = Person() the brother object will be changed because y is brother and assignment operator changes the members of the object.
Never confuse yourself with the & and * operators when dealing with pointer operations.
'&' is used in different context.
&, when used in a function's formal parameters is a reference parameter , this operator passes a variable by reference(by its address).However the variable y still acts like a normal variable.
So this block of code..
void foo(Person &y)
{
y = new Person();
}
would not work as new Person() is parsing a pointer to a variable.
For example,
int * intp = new int;
int variable = intp;
this is the type of thing that's happening here.A reference parameter acts like a variable but actually has direct access to the variable due to the fact that it's a call by referance operation.
The correct way to write this function will look like this
void foo(Person ** y)
{
*y = new Person();
}
That is if you're trying to initialize a class pointer via a function.
As cooky said this is a misconception people make in c++ whom program in languages that require the new keywork in order to create an object/variable.
SOURCES
http://fredosaurus.com/notes-cpp/functions/refparams.html
you are tryng to call the "new" operator on a reference. while the "new" is used only with pointers.
pass to void foo( ) function
Person*
instead of
Person&
A little explanation :
The right way to pass a parameter depends on what you have to do!!
If you want to do side effects to the object passed to the function the right way is to declare :
void foo(Person& person)
the object person can be modified..
if you don t waant to do side effects to the object you have to declare the object 'const':
void foo(const Person& person)
the const means you cannot modify the object inside your method even if you are passing a reference..
then you can pass a pointer:
void foo(Person* person)
here you can modify the object that "person" is pointing at, but you have a copy of the original pointer.
last way to pass parameters is :
void foo(Person*& person)
here you have an alias of the original pointer. alias means "the same pointer with a different name"

Newbie Site fault issue C++

I'm working on a project where I create bank accounts and able to deposit and withdraw. I am to create two bank account and two people- one one the stack and the other on the heap. I should deposit and withdraw into each twice and get the balance print the name and ID and account numbers. At the moment I'm get what I believe is a site fault , reading or writing to protected memory. I've left comments on where I think the errors lie. I would appreciate any help. Thanks.
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
double *balance;
int *accountNumber;
public:
BankAccount(){//default constructor
*balance = 0.0;/***This is where is says the Access violation lies*/
*accountNumber = 0;
}
BankAccount(double bal, int acctNum){//constructor
balance = new double(bal);
accountNumber = new int(acctNum);
}
~BankAccount() {delete balance; delete accountNumber;}
void Deposit(double amt) {
*balance = *balance + amt;
}
virtual double GetBalance() {
return *balance;
}
virtual double GetAccountNumber() {
return *accountNumber;
}
virtual double Withdraw(double amt) {
*balance = *balance - amt;
return *balance;
}
};
class Person {
string *name;
int *ID;
public:
Person(){//default constructor
*name = "name not yet defined";
*ID = 0;
}
Person(string nameIn, int idIn){//constructor
name = new string(nameIn);
ID = new int(idIn);
}
virtual int GetID() {
return *ID;
}
virtual string GetName() {
return *name;
}
};
class NamedBankAccount: public BankAccount {
private:
Person *owner;
public:
NamedBankAccount(){
}
NamedBankAccount(Person *p): owner(p){/***This is where is says the Access violation lies*/
p = new Person();
}
~NamedBankAccount(){delete owner;}
Person getPerson() {
return *owner;
}
};
int main() {
Person *q = new Person("Joe", 54321);
cout << q->GetName() << endl;
cout << q->GetID() << endl;
NamedBankAccount nba1;/***This is where is says the Access violation lies*/
NamedBankAccount *nba2 = new NamedBankAccount(q);
nba1.Deposit(50);
nba1.Deposit(50);
nba1.Withdraw(25);
cout << nba1.GetBalance() <<endl;//should print 75
nba2->Deposit(60);
nba2->Deposit(60);
nba2->Withdraw(20);
cout << nba2->GetBalance() << endl;//should print 100
getchar();
return 0;
}
Do not use pointers here. Just have those strings and integers be member variables. For the specific problem - you haven't allocated any memory before assignment in the default constructor.
Do something like:
class BankAccount {
private:
double balance;
int accountNumber;
public:
BankAccount() :
balance( 0.0 ),
accountNumber( 0 ) {}
// ...
Edit:
Couple of more points about your code:
make use of initialization list in the constructors instead of assignment to member variables - this avoids two-step process of first default-initializing the members and then assigning to them
base polymorphic classes should have virtual destructors, so instances of derived classes could be properly destroyed via pointer to base
polymorphic types usually need to follow the rule of three to avoid slicing
do not make all member functions of a base class virtual, only those you want derived classes to override
think before making a type polymorphic - do you really have bank accounts without owners? Maybe that can be just a value type?
make accessor methods const, so you can get information from const instances
check for errors (you sure don't want to allow withdrawals from zero or negative balance accounts)
"do not use pointers" is a bit strong but what Nikolai means is that member variables shouldn't be pointers to base types but just those types
i.e. in BankAccount, balance should just be an double and not a double* like wise for the others
or have BankAccount() call BankAccount(0.0, 0) as that will allocate the fields right like wise for Person() but unexpectedly this doesn't do what i thought it would in C++ as Karl Knechtel remarks
You are dereferencing an uninitialized pointer, if you change their places it would still do the same thing.
You see, c++ (and c) uses pointers as addresses to memory, if you don't initialize then they will point to anywhere in memory, so dereferencing will PROBABLY cause access violation (probably because you don't know were your pointer points to).
The correct way would be:
BankAccount(){//default constructor
balance = new double; // Initialize pointer (make it points to a valid memory address)
*balance = 0.0; // Give a value to the variable where balance is pointing
accountNumber = new int; // Initialize pointer (make it points to a valid memory address)
*accountNumber = 0; // Give a value to the variable where balance is pointing
}
OR, if you want to allocate memory latter:
BankAccount(){//default constructor
balance = 0; // Make it point to address 0 (conventional value meaning it is uninitialized)
accountNumber = 0; // Make it point to address 0 (conventional value meaning it is uninitialized)
}
Of course, as stated, in your case it would probably be best to use normal variables and not pointers. You should read more about pointers before using them, they can be a pain (I think I speak here on behalf of 99.999% of C and C++ programmers, we've all been there).