What is a good practice for the return of a private member of a "large" class?
typedef std::vector <std::vector <int>> DataType;
class MyClass
{
public:
const DataType &getData() const;
DataType getData2() const;
private:
DataType data;
};
const DataType &MyClass::getData1() const
{
return data;
}
DataType MyClass::getData2() const
{
return data;
}
Shouldn't you copy it using getData1 ()? Is there any performance advantage to prefer a const reference over getData2 ()? How do I get such a "big" private member back from the class?
The difference is what users can do with your DataType
:
- c
getData1
they can only call marked member functionsconst
and access the member variables as if they were declared constant, and only for the entire life cycle of the object that was returning a reference. - c,
getData2
users can call whatever methods they want and make the necessary changes.
The cost of use is getData2
copied: if it DataType
has an expensive copy constructor, the calls can become significantly more expensive.
You can improve this by implementing a copy-on-write and reference-counted communication strategy. Of course, users will be able to make copies manually by calling the permalink copy constructor:
DataType dtCopy(obj.getData1());
Returning a private class to a large class is almost never good practice.
In this example, it appears that the element is data
actually part of the interface. It is not clear if you are going to change the data after creating the class. If not, you can simply expose the const data member as "data as interface" like this:
typedef std::vector <std::vector <int>> DataType;
class MyClass
{
public:
MyClass(DataType data_)
: data(std::move(data_))
{
}
// data is interface, but it immutable so perfectly safe
const DataType data;
};
which will be optimally efficient in all cases, plus it has the advantage of being automatically thread safe.
If you assume what data
is mutable, then it is common to provide a const-backed helper plus a mutable reference accessor (although this is actually logically equivalent to simply displaying data on an interface)
something like that:
class MyClass
{
public:
MyClass(DataType data)
: _data(std::move(data))
{
}
// immutable access
const DataType& data() const { return _data; }
// mutable access
DataType& data() { return _data; }
// another option - allow the client to move the data out of me
DataType&& steal_data() {
return std::move(_data);
}
private:
DataType _data;
};
Returning by constant reference is preferred in this case, as it avoids unnecessary copying.
You should be using getData1 () and not getData2 (). Copying is not required there.
The reason for preference getData1()
is what the client can do const DataType& data = myClass.getData1();
to avoid copying big data.
It depends. It is generally best to return a reference to a const object, you are not 100% sure that your client will need a copy of the data. Even if your client needs a copy of the data, they can call the copy constructor on their side. Thus, getData1()
allows you to use some parameters. Since getData2()
you always have to deal with the copy constructor.
const DataType & MyClass::getData1() const
{
return data;
}
^ This will return a persistent object reference. This is the way. Obviously, this will not allow external modification of the object.
DataType MyClass::getData2() const
{
return data;
}
^ And this is not for "cool kids". This will call your huge object copy constructor on return data
.