Suppose that Foo
is a rather large data structure. How should I write a const
virtual function that returns an instance of Foo
, if I don't know whether the inherited classes will store the instance of Foo
internally; thus, allowing a return by reference. If I can't store it internally, my understanding is I can't return a const
reference to it because it will be a temporary. Is this correct? The two options are:
virtual Foo foo() const { ... }
virtual Foo const & foo() const { ... }
Here's a related question but from a different angle.
You're interested in the difference between a value return and a const reference return solely as a matter of optimization, but it isn't. There's a fundamentally different meaning between returning a different value each time, vs. returning a reference each time, quite possibly to the same object, which quite possibly could be modified:
const Foo &a = myobj.foo();
myobj.modify_the_foo();
const Foo &b = myobj.foo();
a == b; // do you want this to be true or false?
The caller needs to know which it is, both because the programmer needs to know the meaning and because the compiler needs to know the calling convention, so you can't mix them in different overrides of the same virtual function. If some derived classes want to do one, and some want to do the other, then that's tough luck, they can't, any more than one can return an int
and another a float
.
You could perhaps return a shared_ptr
. That way, the derived classes that "want" to return a reference can create a shared_ptr
with a deleter that does nothing (but beware - the shared_ptr
will dangle if the original object is destroyed, and that's not what you normally expect from a returned shared_ptr
. So if it makes sense for the Foo
to outlive the object it came from then it would be better for the class to dynamically allocate it, hold it via a shared_ptr
, and return a copy of that, rather than a do-nothing deleter). The derived classes that "want" to return a value can allocate a new one each time. Since Foo
is "rather large", hopefully the cost of the shared_ptr
and the dynamic allocation isn't too painful compared with what you'd do anyway to create a new value to return.
Another possibility is to turn Foo
into a small pImpl-style class that references a rather large data structure. If everything involved is immutable, then the "want to return a reference" case can share the large data structure between multiple Foo
instances. Even if it isn't, you can think about copy-on-write.
I see that you haven't listed C++0x as a tag, but as reference for anyone with your needs plus access to C++0x, perhaps the best way is to return a std::unique_ptr<>
.
Here's one way:
struct K
{
int ii;
};
class I
{
virtual K &get_k(int i)=0;
};
class Impl : public I
{
K &get_k(int i) { kk.ii = i; return kk; }
K kk;
};
What makes it work is that you use K kk; inside the same object as data member. A constructor for Impl class might be useful too.
EDiT: changing formatting of the code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With