Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Return by reference

125 views
Skip to first unread message

Giuliano Bertoletti

unread,
Feb 9, 2014, 6:50:38 AM2/9/14
to

Hello,

I've a classes like this:

class SubObject { ... };

class Object {
public:
SubObject sub;
};

class MyClass {
public:
Object obj;

public:
SubObject &GetSubObject() { return obj.sub; } // shortcut
};

which is the difference of calling?

==================
MyClass c;

SubObject &sub = c.GetSubObject();
SubObject sub = c.GetSubObject();
==================

It compiles both ways.

In practice I've an higher number of nested classes, so GetSubObject()
is actually a shortcut which digs deep into MyClass and retrieves the
item I need.

Giulio.








Marcel Müller

unread,
Feb 9, 2014, 7:04:19 AM2/9/14
to
On 09.02.14 12.50, Giuliano Bertoletti wrote:
> which is the difference of calling?
>
> ==================
> MyClass c;
>
> SubObject &sub = c.GetSubObject();
> SubObject sub = c.GetSubObject();
> ==================

The second line creates a copy of SubObject. It is in fact another
syntax for the following constructor call:

SubObject sub(GetSubObject());

This /might/ be expensive if copying SubObject is expensive. Furthermore
changes to sub do not apply to c.GetSubObject().

In general you should prefer references for non-trivial data types
unless you have good reasons not to do so.


Marcel

Message has been deleted

Jorgen Grahn

unread,
Feb 9, 2014, 7:58:43 AM2/9/14
to
Depends a lot on the circumstances. If it's clear that the lifetime
of 'SubObject& sub' is shorter than whatever it's referencing, then
sure. If not ... very bad things can happen if the object dies and he
uses that reference to it.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Luca Risolia

unread,
Feb 9, 2014, 7:05:21 AM2/9/14
to
Jorgen Grahn wrote:

> Depends a lot on the circumstances. If it's clear that the lifetime
> of 'SubObject& sub' is shorter than whatever it's referencing, then
> sure. If not ... very bad things can happen if the object dies and he
> uses that reference to it.

class MyClass : public std::enable_shared_from_this<MyClass> {
public:
Object obj;

public:
std::shared_ptr<SubObject> GetSubObject() {
return std::shared_ptr<SubObject>(shared_from_this(), &obj.sub);
}
};

auto c = std::make_shared<MyClass>();
auto sub = c->GetSubObject(); // c.use_count() is 2

Jorgen Grahn

unread,
Feb 9, 2014, 8:07:52 AM2/9/14
to
You might want to review that design to see if there is a smarter way
of doing it. You're saying you drill past three or more levels to get
that object, and that seems unusual. Perhaps your classes are too
much like dumb data containers, and you could change them to contain
more of the intelligence?

On the other hand, dumb data containers aren't always a bad idea ...

By the way, don't forget the third form:

const SubObject& sub = c.GetSubObject();

Here you're still at the mercy of whoever owns the object, but at
least you're promising not to modify it without informing the owner.

It's rather common to only need read access to something. This way
you can document it, and the code will IMO be significantly easier
to read.

Luca Risolia

unread,
Feb 9, 2014, 7:21:40 AM2/9/14
to
Giuliano Bertoletti wrote:
> SubObject &sub = c.GetSubObject();

Don't return references to sub objects. To safely share (sub)objects in memory
use smart pointers.

> SubObject sub = c.GetSubObject();

This is a copy and is safe.

If you read the answer I have given in my other answer, you will probably see
the difference better.

Giuliano Bertoletti

unread,
Feb 9, 2014, 8:43:10 AM2/9/14
to

ok, thank you.

Is it then safe to call:

c.GetSubObject().SomeFunction()

and expect a straight invocation of the original subobject (not a copy)?

Giulio.

David Harmon

unread,
Feb 9, 2014, 2:15:04 PM2/9/14
to
On Sun, 09 Feb 2014 13:21:40 +0100 in comp.lang.c++, Luca Risolia
<luca.r...@linux-projects.org> wrote,
>Don't return references to sub objects.

Correct.
In general, your subobjects should belong only to you.

https://en.wikipedia.org/wiki/Law_of_Demeter
http://www.ccs.neu.edu/home/lieber/LoD.html
https://duckduckgo.com/html/?q=law+of+demeter

Message has been deleted

Stuart

unread,
Feb 10, 2014, 7:35:36 AM2/10/14
to
>>>On 02/09/14, Giuliano Bertoletti wrote:
>>> which is the difference of calling?
[snip]
>>> ==================
>>> MyClass c;
>>>
>>> SubObject &sub = c.GetSubObject();
>>> SubObject sub = c.GetSubObject();

On 09/02/2014, Marcel Müller wrote:
>> The second line creates a copy of SubObject.
[snip]

On 02/09/14, Giuliano Bertoletti wrote:> ok, thank you.
>
> Is it then safe to call:
>
> c.GetSubObject().SomeFunction()
>
> and expect a straight invocation of the original subobject (not a copy)?

That's right.

Note that such design is frowned upon by some people because it makes
the contract MyClass harder to grasp: Whoever gets access to the
instance of MyClass can also manipulate the sub-object at will. This way
it is not clear why the sub-object is a sub-object of MyClass and not
just an ordinary object that can be manipulated by both MyClass and
everybody else.

If you return a const reference (const SubObject&), however, it becomes
much clearer. The MyClass has full access to the sub-objects, but
clients of MyClass can no longer change MyClass's sub-object but only
retrieve information from it.

Regards,
Stuart

James Kanze

unread,
Feb 14, 2014, 4:34:17 AM2/14/14
to
On Sunday, 9 February 2014 12:04:19 UTC, Marcel Müller wrote:
> On 09.02.14 12.50, Giuliano Bertoletti wrote:
> > which is the difference of calling?

> > ==================
> > MyClass c;

> > SubObject &sub = c.GetSubObject();
> > SubObject sub = c.GetSubObject();
> > ==================

> The second line creates a copy of SubObject. It is in fact another
> syntax for the following constructor call:

> SubObject sub(GetSubObject());

> This /might/ be expensive if copying SubObject is expensive. Furthermore
> changes to sub do not apply to c.GetSubObject().

Whether the changes should apply or not is the key. Reference
semantics and value semantics are two different things.

> In general you should prefer references for non-trivial data types
> unless you have good reasons not to do so.

Not for return values. References lock you in; once you return
a reference, you can never return a synthesized value. The
general rule is to return by value unless the intent is to
furnish access to an element of the object (e.g. things like the
operator[] of vector).

--
James

James Kanze

unread,
Feb 14, 2014, 4:38:08 AM2/14/14
to
On Sunday, 9 February 2014 12:21:40 UTC, Luca Risolia wrote:
> Giuliano Bertoletti wrote:

> > SubObject &sub = c.GetSubObject();

> Don't return references to sub objects.

That depends on the role of the class. Things like
std::vector<>::operator[] should certainly return a reference.

> To safely share (sub)objects in memory use smart pointers.

I can't really think of a situation where I'd want to "share" an
object. An object will normally either be independant (an
entity object, owned by no one), or part of another object.

--
James

Luca Risolia

unread,
Feb 14, 2014, 1:20:49 PM2/14/14
to
James Kanze wrote:

>> > SubObject &sub = c.GetSubObject();
>
>> Don't return references to sub objects.
>
> That depends on the role of the class. Things like
> std::vector<>::operator[] should certainly return a reference.

>> To safely share (sub)objects in memory use smart pointers.
>
> I can't really think of a situation where I'd want to "share" an
> object. An object will normally either be independant (an
> entity object, owned by no one), or part of another object.

Look at the example I gave in my other answer to this post to know what
sharing means with regard to the OP question. There you will certainly notice
that the term "share" is used in two standard function names at least. That
example should make the concept more clear to you and also answer to both your
previous observations.

0 new messages