bpgeck bpgeck - 2 months ago 18
C++ Question

Cannot assign to non-static data member within const member function

I am attempting to use

std::unordered_set
as a hash table to store many
CreditCard
's.
CreditCard
and another class
CardDatabase
are defined as follows:

class CreditCard {
private:
string cardHolder;
unsigned long long cardNumber;
int limit;
int balance;

public:
CreditCard(string in_cardHolder, string in_cardNumber, int in_limit) {
cardHolder = in_cardHolder;
cardNumber = stoll(in_cardNumber);
limit = in_limit;
balance = 0;
}

void ChangeBalance(int amount) const {
balance += amount; // SECOND ERROR
}
};

class CardDatabase {
private:
unordered_set<CreditCard> cards;
unordered_set<CreditCard>::iterator iter;

public:
CardDatabase() { }

void AddCard(cardHolder, cardNumber, int limit) {
CreditCard tempCard = CreditCard(cardHolder, cardNumber, limit);
cards.insert(tempCard);
}

void Charge(string cardHolder, int chargeAmount) {
iter = cards.find(cardHolder);
iter->ChangeBalance(chargeAmount); // FIRST ERROR
}
}


Initially I was getting the following compile error at
FIRST ERROR
:
Member function 'ChangeBalance' not viable: 'this' argument has type 'const CreditCard', but function is not marked const
. So, I added the "const" to the
ChangeBalance
function. However, after doing that I get the following compile error at
SECOND ERROR
:
Cannot assign to non-static member within const member function 'ChangeBalance'
.

Is there any way to fix this error without changing
balance
to a static variable? It is obviously important that the balance be different for each
CreditCard
instance.

Any help is appreciated.

EDIT:



Thank you all for your quick answers. I feel I should clarify something. I already added the proper hash functionality elsewhere in my code:

namespace std {
template <>
struct hash<CreditCard> {
size_t operator()(const CreditCard& cc) const
{
return hash<string>()(cc.GetCardHolder());
}
}
}


Also, the code I posted initially pasted is from a much larger code base and I didn't delete all the necessary namespacing stuff at first before posting the question. My apologies for the confusion.

Answer

Members of an unordered_set are constant, and cannot be changed once they're in the unordered_set, by default. You are trying to change the objects in the set, and the compiler is properly telling you that you can't do this.

The only possible way to do this correctly (explained only for educational purposes, because this is bad class design):

  1. Explicitly declare the individual fields that can be modified in this manner as mutable.

  2. Use a custom hash function with your unordered_set, and the hash function must exclude the value of mutable fields from the value of the calculated hash.

Otherwise, modifying the contents of the object in the set obviously changes its hash value, which will result in undefined behavior.

Again, this is explained for informational purposes only. This is not a good class design.

The clean way to do this would be to assign a unique identifier to each CreditCard (you know, like a credit card number?), and use an ordinary std::map, to look up CreditCards by their number.