Class Member Variable not Saving State - c++

I'm new to C/C++, so people excuse me if this is a noob question.
I have a controller class, which has a private member variable which is a vector<Contact> contacts. The class has methods which allow us to change the state of this vector (standard CRUD operations).
The class has a public method called get_contacts() which returns this private vector of objects:
std::vector<Contact> Contacts_Controller::get_contacts() const {
return this->contacts;
}
I have a method which adds the contact to this private vector via push_back(). The issue is that if the add_contact() method uses the accessor method, then the class variable does not get updated:
void Contacts_Controller::add_contact(const Contact &contact) {
this->get_contacts().push_back(contact);
}
I assume this is a memory issue, perhaps I have some issues with my use of const or I'm not correctly using references, because the following code works exactly as expected:
void Contacts_Controller::add_contact(const Contact &contact) {
this->contacts.push_back(contact);
}
Using either method won't return any errors, but if I then request the vector of contacts after using the first method it'll be empty, whereas the second method correctly adds data to the vector.
Again, sorry if this is a noob question, but I'm completely stumped, and I wouldn't know what to search for! How would I fix this referencing issue?

"The class has a public method called get_contacts() which returns this private vector of objects"
Nope, it returns a copy. You need to return by reference to get the actual member:
std::vector<Contact>& Contacts_Controller::get_contacts(){
return this->contacts;
}
Note that I removed the const, otherwise you'd have to mark the return as const also and you wouldn't be able to modify it.

The issue is that your function is returning the vector by value, which means the calling function gets a copy.
When you call push_back() on it, only the copy gets the extra member.
Your function could return a reference. Then your user can call push_back(). If it is a member variable of your class and you are returning a non-const reference (which you must to allow the modification) your function will probably also be non-const.
Thus:
std::vector<Contact> & Contacts_Controller::get_contacts() // not const
{ return this->contacts; }
You can also have a read-only version, as an overload.
std::vector<Contact> const & Contacts_Controller::get_contacts() const
{ return this->contacts; }
This version allows read-only access to the contacts and can also be a const member function.

When you call get_contacts, you return a copy of this->contacts. If you want to share a vector, either return a reference to it (but you must be sure that your reference will stay valid so your class instance won't be moved or copied), or use a smart pointer to dynamically allocate the space for your vector and extend its lifetime until the last reference to it has been destructed. In this case use a member with type std::shared_ptr<std::vector<Contact> >

Related

Accessing class member of std:vector of std:vector in a class with another std:vector

I am puzzled by how to access a std::vector in a class with another a std::vector. A previous discussion(Why is it OK to return a 'vector' from a function?) deals with a similar issue, but it seems I must have misunderstood something.
Here is a sketch of my code:
class Employee
m_id;
public:
set_id(int id);
id();
In Employee.cpp
void Employee::set_id(const int id)
{
m_id = id; // m_id is 5
}
int Employee::id() const
{
return m_id; // m_id is rubbish
}
class Company
public:
std::vector<Employee> m_employees;
In Company.cpp
void Company::addEmployee(const addEmployee employee) // A vant to pass a copy of employee
{
m_employees.push_back(employee);
}
std::vector<Employee> Company::employees()
{
return m_employees;
}
in myClass.h
std::vector<Company> m_companies;
in myClass.cpp
int empl_id = 5; // test value
m_companyIndex = 0; // for test
m_emplIndex = 0; //
Company company;
Employee employee;
m_companies.push_back(company);
m_companies.at(m_companyIndex).addEmployee(employee);
m_companies.at(m_companyIndex).employees().at(m_emplIndex).set_id(empl_id);
int idRet = m_companies.at(m_companyIndex).employees().at(m_emplIndex).id();
idRet contans an apparently random number, instead of 5. Using a debugger shos that
If I instantiate Employee in myClass I can set and read back m_id; idem for Company, so the problem seems to be realted to std::vector m_employees; in class Company. Could it have something to do with "Return Value Optimisation"? By the way, I am using gcc 7.5.4.
As #dxiv points out, your Company::employees function constructs and returns a copy of the m_employees list. Thus your code
m_companies.at(m_companyIndex).employees().at(m_emplIndex).set_id(empl_id);
translates to:
Get the element of m_companies at the index m_companyIndex,
then construct a copy of its m_employees list,
then get the element of that copy at index m_emplIndex,
then set the id of that element to empl_id,
and then destroy the copy.
This of course does not change the contents of the m_employees list at all.
You could make your code work more or less correctly by making Company::employees return a non-const reference to the employees list, rather than a copy. However, such a function could not be called on a 'const' Company object, so you would probably also want a 'const' version of it that returned a const reference as well.
However, exposing a class's private implementation details, such as m_employees, even via a non-const reference, is dangerous, because if outside code uses this reference to modify the m_employees vector, then the Employees class is not notified, and any other internal data that it has which may depend on the contents of the m_employees vector can't be updated at the same time.
It is therefore generally better for outside code to ask the containing class (Employees) to make the change rather than asking the containing class to return a non-const reference that can be used by outside code to make the change. That way, the Employees class can make the change and also update any other internal data that it has that may depend on the m_employees contents.
For instance, you could add an Employees::at function which returns a reference to an element so that the above line of code could be rewritten as:
m_companies.at(m_companyIndex).at(m_emplIndex).set_id(empl_id);
or even better:
m_companies.at(m_companyIndex).set_id(m_emplIndex, empl_id);
or even better, if m_companies was contained in a Companies object named 'companies':
companies.set_id(m_companyIndex, m_emplIndex, empl_id);
With these functions, you could change Employees::m_employees to use a completely different data structure (say, a sorted list, linked list or set) without affecting your interface at all. This reduces the coupling between outside code and the internals of your class, and makes things easier to change in the future if you need to.
In general, it's wise to consider the Law of Demeter when designing interfaces of this sort, especially with regard to interfaces for mutating the contents of objects: Many objects don't react well to having their internal contents changed by outside classes without their knowledge, so it's best to ask the containing object to change its subobjects when possible, rather than allowing non-const references to them to be accessible from outside the class.

Is returning a class member a bad practice?

Given:
Class A
{
private:
double **CR;
public:
double **compute2D();
};
Suppose that I have a private 2D Array member:
double **CR;
And I have a member function:
Double ** Compute2D()
Function computer2D will return CR.
Is this a bad practice?
Why?
Should I use the getter and setter functions to return it?
And one more question: Am I using the garbage collector correctly?
A::~A()
{
//Delete 2D array
for(int i = 0; i < Rows; ++i)
{
delete [] CR[i];
}
delete [] CR;
}
By doing this, you allow changing private member value, outside of the class. It is up to you if it is bad or good. But in my opinion, if I have a private member, then I must be the only one who can change its value.
It's bad to return a pointer to private member of your class because it can break encapsulation. Somebody will be able to change value of private variable without
inform your class about it. However there is nothing bad in return copy of fields of your class.
When using getter and setter there is no way to change class state without class knowing about it. So that's nice practice.
With deleting an array everything looks ok.
it is bad because you are returning private variable with writing access, maybe it is not so private
it is bad bacause you are returning a pointer, in this case it is not clear who has the responsibility to free the memory: the class because it is its own member or the user since he call the method?
Returning a class member is alright. However in your case I would do it slightly different. You return pointers to a 2D vector. This way you can return the result of you calculations you don't have to make a copy of the data. And since it returns a const value you are sure the caller will not be able to change the data, but can use it to read the values.
Class B
{
private:
vector<vector<double> > CR; /*note space between > > is significant*/
public:
const vector<vector<double> >& compute2D(){
/*do calculation here eg.*/
return CR;
}
};
And since my example show this how you can do this using std::vector you don't have to wory about deleting the dynamically reserved memory. You must make sure the instance of Class B is not destroyed eg by going out of scope if you are still using the reference variable.
If you return a pointer or non-const reference to your private data member via a public method, it is pointless to make it private. You could make the property public as well.
This basically means you allow to manipulate the member outside of the class. IMO this is considered a bad practice, or even an anti-pattern because the class cannot depend on its own state. This is very important.
E.g: imagine you have a pointer, and somebody sets it to null. Even the private methods would need to check for it, even if internally such state is impossible to reach.
Returning normal members, such as classes is considered a bad practice because it involves copying of whole objects. Usually it is better to return a reference or probably preferably const reference.
The getters in turn would allow you to put const constraints. In both cases, pointers and references.
Also please note, that in such cases usually, one provides two methods. compute and get. Currently you can access your member only by computing it!
I won't go so far to suggest you to switch to std::vector as I do not know what you need, and vectors are not good for everything. So sticking with pointers, this is the safe way to go:
class A
{
private:
double **CR;
public:
double const * const * compute2D();
double const * const * getCR();
};
double const * const * A::compute2D(){
return CR;
}
double const * const * A::compute2D(){
/*Heave CPU stuff*/
return CR;
}
int main(){
A a;
double const* const* tmp = a.compute2D();
tmp[1][2] = 0; //this will fail to compile
tmp[1] = 0; //this will fail too
double get_test = tmp[1][2]; // this passes!
}
Notice double const qualifiers. It is important to protect each level of pointer references.
Reterning a class method is perfectly fine if you want that class member to be readable outside the class, which is completely dependent upon what you're trying to accomplish. As for using a getter method, you already are; it is "good practice" to use such methods to create a more uniform, encapsulated setup for your class and therefore make it easier to edit the class later. Even if your function does other things (in this case, computes something in two dimensions), it's still a getter method.
In this particular case, however, you're not returning a value; you're returning a double pointer to a value. This means that the user will be able to edit the data (which I'm guessing is an array) ouside the class, which is NOT a good thing. You should perform a deep copy of the data before returning it.
As for using the garbage collector correctly: yes, you are. Although it's not called a garbage collector in C++, it's simply called freeing memory; a garbage collector is the name for a system that frees memory automatically.

Returning strings by reference cpp

Forgive me if this has been asked before, I am sure it has but I couldn't find an answer I was happy with.
I am coming to cpp from a heavy Java background and would like to understand when to return a reference/pointer to an object rather than a copy.
for the following class definition:
class SpaceShip {
string name;
WeaponSystem weaponSystem; //represents some object, this is just an example, I dont have this type of object at all in my program
int hull;
string GetName() const {
return name;
}
WeaponSystem GetWeaponSystem() const {
return weaponSystem;
}
int GetHull() const {
return hull;
}
};
I know that returning a copy of things is expensive, I would think this means I want to avoid returning something like a string or weaponSystem by value, but an int by value is ok.
Is this right? I also know that I need to be aware of where things live in memory, does returning a reference to something in this class mean danger down the line if this object is destroyed and something still owns a reference to it's name?
On your last point, you definitely need to be a lot more careful about resource management in C++ than in Java. In particular, you need to decide when an object is no longer needed. Returning by reference has an effect of aliasing to the returned object. It is not noticeable when the object you are sharing is immutable, but unlike Java's Strings, C++ string are mutable. Therefore if you return name by value and then rename your SpaceShip, the caller would see the old name even after the renaming. If you return by reference, however, the caller will see a change as soon as ShaceShip is renamed.
When you deal with copying complex objects, you can decide how much is copied by providing a custom implementation of a copy constructor. If you decide to provide a copy constructor, don't forget the rule of three, and override the other two.
It "works" but you should have
const string& GetName() const {
It may also be beneficial to have the following also
const WeaponSystem& GetWeaponSystem() const {
Also, class is private by default, as such, your accessor functions are private.
the thing you have to know is every getter of your class must be prototype like that :
const <type> &className::getXXX() const
{
...
}
and every setter you make like that :
void className::setXXX(const <type> &)
{
...
}
Use reference when it's possible.
Sometimes, with complex object you can use pointer. That's depend on your code structure.

Best way to return an object in c++?

I'm pretty noobish when it comes to c++, what is the better way of returning an object? I'm coming from the scripting world where Objects are always references, and am trying to achieve the same notion ... I'm basing this off of When to pass by reference and when to pass by pointer in C++?, where one user stated: "A good rule of thumb: "Use references when you can and pointers when you have to"."
// basic layer class
class Layer { private: Channel channel; // NEVER NULL };
// return object by pointer
Channel *Layer::getChannel() {
return &channel;
};
// return by reference
Channel& Layer::getChannel() {
return channel;
};
The problem with the second version is that the compiler will accept this line:
Channel channel = layer.getChannel(); // creates a copy BAD
when it should be:
Channel &channel = layer.getChannel(); // reference good
Is there any way to enforce a caller of the second option to force it to not create a new channel, or is the first option better anyways, even if it will never be NULL?
You need to adjust the Channel class itself so that it isn't copyable. If it is copyable, the user can copy it, and nothing you do can prevent it.
If copying is not a meaningful operation, then you can "disable" it. Simply define the copy constructor (Channel(const Channel&)) and the assignment operator (Channel& operator=(const Channel&)) to be private. Then any attempt at copying the class will result in a compile error.
On a side note, as others have mentioned, C++ is not the scripting languages you're familiar with. Everything is not a reference, and you're only setting yourself up for a world of pain by pretending otherwise. In C++, it is common to allocate objects on the stack, and pass objects by value, rather than passing references and pointers around.
Returning a reference (or const reference) is the normal way for a getter method to give the caller direct access to a member variable, so I'd recommend the second version of getChannel().
If you want to prevent callers from making inappropriate copies of Channel, you can accomplish that by making its copy constructor private. (If you want to prevent everything from making copies, even Channel itself, you can declare the constructor private and then not implement it.) But you should only do this if making a copy would actually be nonsensical, e.g. if the class represents some sort of underlying resource that can't be copied. Don't forbid copying just because you think the caller shouldn't need to; that's the caller's decision to make.
Return a copy of the object itself when copying isn't expensive for your purposes, and when you don't need to be able to change the original. This should be the default.
Channel Layer::getChannel() { return channel; };
Return by reference or pointer when copying is expensive or when you might want to change the value. Returning by reference allows you do to things like this:
layer.getChannel().clear();
And have it act on the channel that's in that layer.
Returning a pointer is similar to returning a reference except that it gives you a little more flexibility, in that the pointer can pointer to no object at all. I often a pointer when I want to be able to use store the "channel" in another class. I'd then do
class MyClass
{
// ...
void setChannel(Channel *pC) { m_pChannel = pC; }
private:
Channel * m_pChannel; // pointer to a channel that came from layer
}
Since you're returning a reference to the object, you are giving the users of the class direct access to the object, and if you're going to do that, why are you making the object private? Just make it public.
You can't stop a caller to create a new instance even when you use the pointer-return-version.
Channel* channel = new Channel(*layer.getChannel());
I know there is a way to achieve this goal. (For example, making Channle's ctor private so only it's static member function or its friend functions can create it.) However, I don't think this is the point of your question.
The point is that when you are making the member function returning either reference or pointer, you give a caller options he can choose whether he wants to copy it or reference it. Also, you can make your intention more clear by adding const to make it read-only.
For your case, I'd go for reference-return-version as the Channel cannot be null. If you do not want them to change the member variable, return const reference. Remember there is no single best way to decide return value type as it depends on what you want to say. Hope it helps! :)
Most important is maintaining readability with the code that's around you. "When in Rome, do as the Romans do." is important. You write it once, but everyone who has to maintain your code has to read it. If all of a sudden your code follows different guidelines than everyone around you, that means they need to first figure out your style, then figure out what you're doing...
One approach I've seen work very well is having pointers for things you change and const references for things you don't:
class Passenger {
...
};
class Car {
public:
int speed() const { return speed_; }
void set_speed(int speed) { speed_ = speed; }
const Passenger& passenger() const { return pass_;}
Passenger* mutable_passenger() { return &pass_; }
private:
int speed_;
Passenger pass_;
};
Clients of this class can do:
const Passenger& pass = car.passenger(); // no copy, but don't need to deal with NULL ptrs.
Other answers suggesting making copying a compile error are good ones.

Storing local variable in std::map

I have a class Message and a class Cache.
In Message::processMessage() fn. I create a instance of another class CacheRef(not shown below.)
then I call Cache::cacheData(cacheRef)
Now, in Cache class, I have a map which has its key as CacheReference. I store the ref that I passed to cacheData fn. in this map.
class Message
{
private:
Key m_key;
public:
void processMessage(int a, int b, Cache *pCache)
{
CacheRef ref(a, b, m_key); //CacheRef is a class defined in same file
//some char *data - do processing an dfill it!!
pCache->cacheData(ref, data);
}
}
class Cache
{
public:
void cacheData(CacheRef &ref, const char* data)
{
CacheDir *dir;
std::map<<CacheRef, CacheDir*>::iterator it = m_dirs.find(ref);
if(it == m_dirs.end())
{
dir = new CacheDir();
m_dirs.insert(ref, dir);
}
}
std::map<CacheRef, CacheDir*> m_dirs; //CacheDir is some class defined in the same file
}
Now, the code is working absolutely fine. But I have this concern(not sure!!) that I am storing some local variable in map, which which cease to exist as soon as processMessage()fn. exits. So, am I accessing some invalid memory, is it just by luck that this code is working.
If this is wrong, what is the best way to achieve this behaviour?
I don't have boost on my system, so can't use shared_ptr for anything.
Because the 1st template parameter is a CacheRef (and not a reference or pointer to a CacheRef) then ref will be copied into the map when you do the insert. Hence, you won't be storing a reference to a local stack variable.
As long as there is an appropriate copy constructor or assignment operator for CacheRef then this will work ok.
As Stephen Doyle pointed out, you are actually storing a copy of the CacheRef in the map, not a reference to the one passed to the cacheData() method.
Whether this causes a problem or not depends on the definition of the CacheRef class. If, for example, a CacheRef holds a pointer or a reference to the Key passed to the constructor, you will end up with an invalid pointer once the Message instance is destroyed.
By the way, since you are storing dynamically allocated objects of CacheDir in Cache::m_dirs, you should make sure to delete all values in the map in the Cache::~Cache() destructor to avoid memory leaks.