When writing simple get/set methods in C++, should you always use const references as the parameters? [duplicate]

StackOverflow https://stackoverflow.com/questions/21243444

Question

I'm revising for an upcoming C++ exam in the next few days and looking at past paper answers, every time something simple like a get or set method is called, the parameters are passed as constant references.

Should I always be doing something like this unless I explicitly don't want constant references to take effect?

For example this:

class Person{
string name;
int age;
int niNo;

public:
    Person(const string & _name, const int & _age, const int & ni) : name(_name), age(_age), niNo(ni) {}

string getName() const{
    return name;
}

int getAge() const{
    return age;
}

int getNi() const{
    return niNo;
}

bool operator==(const Person &p){
    return name == p.getName() && age == p.getAge() && niNo == p.getNi();
}
};

class Contacts{
vector<Person> persons;

public:

template <typename T>
void addNewEntry(const T &p){
    persons.push_back(p);
}

template <typename T>
void printAllAges(const T &name){
    for (int i = 0; i < persons.size(); ++i)
    {
        if (persons[i].getName() == name)
            cout << persons[i].getAge() << endl;
    }
}


};

I assume it's faster because passing by value would mean a temporary parameter object is made and the value copied to it. And the constant is just good practise to indicate the value won't be changed?

EDIT: Thanks for clarifying everyone, much appreciated.

Was it helpful?

Solution

Should I always be doing something like this unless I explicitly don't want constant references to take effect?

Yes, although it is a person preference, or some performance concerns. I personally like to pass by reference, but pass by values for primitive types such as int may give you a better performance.

I assume it's faster because passing by value would mean a temporary parameter object is made and the value copied to it.

See above. Yes a temporary copy would be created but a copy of primitive type object may be cheaper.

the constant is just good practise to indicate the value won't be changed?

Yes. It is more a safety practice rather than a performance issue.

You got everything right. No problems at all for the exam :)

OTHER TIPS

In general yes, passing by (const) reference is good idea. In some cases its' better to pass by value - when passed objects are small. And in case of c++ 11 it's not always as clear since you can leverage move semantics to move objects from call site, which should be very cheap - usually coping of one pointer.

For the test itself it's probably safe to pass user defined types by (const) reference and integral types by (const) value.

Actually, if you're sinking an argument, it's better to pass it by value and them std::move it:

Person(std::string name, int age, int ni)
    : name{std::move(name)}, age{age}, ni{ni} { }

Passing a const reference is roughly as expensive as copying a pointer. For it to have advantages over passing a value, copying the value must be significantly more expensive than copying a pointer.

Passing a const reference adds a level of indirection when accessing the referenced object. This indirection might anihilate the performance gain of copying significantly less than the object.

A brief insight on 'by-reference', followed by a few notes on your code above:

When we pass an argument to a function by reference, or return an argument from a function by reference, we in essence pass/return the argument's address.

This address is typically a 4-byte variable on 32-bit systems and an 8-byte variable on 64-bit systems.

So in terms of run-time performance, passing/returning an argument by reference is exactly as passing/returning an argument as pointer. In both cases, a 4-byte / 8-byte value is copied into the stack.

The main advantage of 'by-reference' over 'by-pointer' is during compile-time, when it allows us to refer to the argument directly instead of indirectly. In other words, it allows us to use . instead of ->, and it relieves us from the need to use *.

This proves useful mostly with template classes and functions, which may operate on generic objects.

In contrast, the main advantage of 'by-reference' over 'by-value' is during run-time, in the amount of data being copied into the stack every time an argument is passed to a function or returned by a function.

So while there's an advantage in passing/returning a structure by reference (constant or non-constant), there is no advantage in passing/returning a native variable such as int by reference when it's constant. The amount of data copied into the stack is the same whether we pass it by reference or by value. So if this variable is not supposed to change, then we can simply pass/return it as int instead of as const int&.

Now just a couple of notes (deriving from the above) on your code:

  1. In the Person() constructor, you can pass the arguments as int instead of as const int&.

  2. In the getName() function, you should return const string& instead of as string.

An additional (unrelated) note:

You've declared operator== as a member function of class Person.

If you intend to keep it there, then you might as well declare this function const.

However, you might wanna consider declaring it as a global friend function, in order to allow comparison with an object of some future class, which could be cast to Person. Declaring this operator as a global function will allow you to make the comparison "on both sides" (A == B or B == A).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top