How to use getters and setters without generating a copy?
(If you do not care about encapsulation in this case, meaning the A::object
member should be modifiable by anyone without restriction, then look at SergeyA's answer).
Return by const reference in order to avoid copying and still maintain encapsulation (meaning the caller can't modify the member by mistake):
const BigObject& getObject() const
{
return object;
}
If the caller actually wants a copy, they can do so easily themselves.
If you want to prevent dangling references (the segfault you mentioned) when the getter is used on a temporary, you can only return a copy when the getter is actually called on a temporary:
BigObject getObject() const &&
{
return object;
}
const BigObject& getObject() const &
{
return object;
}
This will return a copy when calling getObject()
on a temporary. Alternatively, you can completely prevent calling the getter on a temporary by deleting that particular overload:
BigObject getObject() const && = delete;
const BigObject& getObject() const &
{
return object;
}
Keep in mind that this is not a guaranteed safety net. It prevents some mistakes, but not all of them. The caller of the function should still be aware about object lifetimes.
You can also improve your setter, btw. Right now, it will always copy the object regardless how the caller passes the argument. You should take it by value instead and move it into the member:
void setObject(BigObject object)
{
this->object = std::move(object);
}
This requires that BigObject
is movable though. If it's not, then this will be even worse than before.
Best solution: make code of your class exactly that:
struct A
{
BigObject object;
};
Explanation - avoid trivial setters and getters. If you find yourself putting those into your classes, expose the member directly and be done with it.
Do not ever listen to people who'd say "But what if in the future we add non-trivial logic"? I have seen more than a healthy dose of trivial setters and getters, been around for decades, and never replaced with something non-trivial.
The common practice is to:
class A
{
public:
// this method is const
const& BigObject getObject() const
{
return object;
}
// this method is not const
void setObject(const BigObject& object)
{
object = object;
}
private:
BigObject object;
};
If you need to get a read-only object - it's perfectly fine. Otherwise, consider changes in architecture.
An alternative would be to store a std::shared_ptr
and return a std::shared_ptr
or std::weak_ptr
.