I have some questions about returing a reference of a class member variable.
I have the following code:
#include <stdint.h>
#include <string>
#include <iostream>
#include <set>
void
PrintSet (const std::string & str, const std::set<uint32_t> & to_print)
{
std::cout << str << " (" << to_print.size () << "): ";
for (std::set<uint32_t>::const_iterator it = to_print.begin ();
it != to_print.end (); ++it)
{
std::cout << *it << " ";
}
std::cout << "\n";
}
class Test
{
private:
std::set<uint32_t> m_values;
public:
Test () : m_values () { }
void
SetValues (const std::set<uint32_t> & values)
{
m_values = values;
}
const std::set<uint32_t> &
GetValues () const
{
return m_values;
}
std::set<uint32_t> &
GetValues ()
{
return m_values;
}
void
Print () const
{
PrintSet ("TestInst", m_values);
}
};
I noticed that if I do this:
std::set<uint32_t> returned = test.GetValues ();
The variable returned
gets a copy, not a reference, why?
Does the const std::set<uint32_t> & GetValues () const
function must contain the double const
(the one on the return value and the one after the function name) ?
EDIT: Additional questions:
Knowing that std::set<uint32_t> returned = test.GetValues ();
creates a copy. If I do this:
test.GetValues ().size ();
In order to call the size ()
function (or any other member of the returned object), is a copy created temporarily or all is resolved with the returned reference?
Is it bad to have three functions, return by value, by const-reference and by reference?
// Return by value
std::set<uint32_t>
GetValues () const
{
return m_values;
}
// Return by const-reference
const std::set<uint32_t> &
GetValues () const
{
return m_values;
}
// Return by reference
std::set<uint32_t> &
GetValues ()
{
return m_values;
}
The variable returned gets a copy, not a reference, why?
When you use a reference to initialize a value whose type is not a reference you get a copy, for example
#include <cassert>
int main() {
int a = 1;
const int& a_ref = a;
int b = a_ref;
assert(&b != &a);
}
Does the
const std::set<uint32_t> & GetValues () const
function must contain the double const
The second const is applied as a member function qualifier, it means that the method can be called when the calling instance of your class is const qualified. For example
Test test;
test.GetValues(); // 1
const Test& test_ref = test;
test_ref.GetValues(); // 2
Here 1
will call the non-const version and 2
will call the method qualified with const
Further a const
qualified method will not let you return non-const references to it's own values, so you must return a const
reference to your member variable m_values
.
So if you include the second const
then you must include the first const
, however if you just make the return type be a const
reference then you don't need to make the method const
. For example
const std::set<uint32_t>& GetValues() // 1
std::set<uint32_t>& GetValues() { return m_values; } // 2
here 1
is allowed but 2
is not allowed.
The reason this happens if you are curious, is because the implicit this
pointer is const
qualified to be a pointer to const
in const
qualified methods.
In order to call the size () function (or any other member of the returned object), is a copy created temporarily or all is resolved with the returned reference?
The size()
method will be called on the reference! The best way to test things like this is to try it out in a quick test case https://wandbox.org/permlink/KGSOXDkQESc8ENPW (note that I have made the test a little more complicated than needed just for demonstration)
Is it bad to have three functions, return by value, by const-reference and by reference?
If you are exposing the user to a mutable reference, then the best way to let them make a copy (which is why you had the by-value) method is to let them make a copy themselves by initializing a non-ref qualified set
with the returned reference (like you did initially)
Also in your code there is am ambiguity between the following two methods
std::set<uint32_t> GetValues() const
const std::set<uint32_t>& GetValues () const
Because all that is different is the return type, and you cannot overload a function off the return type.