In the library I am designing, I sometimes need read-access to large member variables of classes. Because of their size I don't want to make a getter that returns by copying the member. I don't want them to be modifiable from the outside, so I can't have them public or return references to them. So I thought I would use a "reader":
class TestClass
{
public:
explicit TestClass(double d): d_(d){}
const double& readD() const { return d_; }
private:
double d_;
};
(this is not really meant for doubles)
But here somebody could const_cast the reference and access the data directly. Even without assuming malicious intent, somebody could safe a reference to the data-member and keep it around after the original object has gone out of scope. I know const references can keep a temporary viable, but that doesn't remove the const_cast-problem. So I came up with a workaround:
#include <iostream>
template<class T>
class SafeMemberReference
{
public:
using type = T;
SafeMemberReference(const T& t) :t(t) {}
explicit SafeMemberReference(T&& t) = delete;
operator const T& () && {return t; }
T get() && {return t; }
private:
const T& t;
};
class TestClass
{
public:
explicit TestClass(double d): d_(d){}
SafeMemberReference<double> readD() const { return d_; }
private:
double d_;
};
int main()
{
TestClass foo(1.2);
// temporary from read can be used as temporary in expressions
std::cout << foo.readD() << std::endl;
// temporary can be used to copy from
auto x = foo.readD().get();
// lvalue can not be used, so a possible dangling reference is no problem
auto ref = foo.readD();
//std::cout << ref << std::endl;
}
I have several questions to this:
Q1) How necessary is this from an efficiency POV? the largest objects I am returning are dense complex matrices with dimensions of maybe 1000x1000. These copies may happen frequently
Q2) Are my concerns about returning by const& valid?
Q3) Does this seem like a good solution? which drawbacks does it have?