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

References, AddressOf and Object management

0 views
Skip to first unread message

Tim Clacy

unread,
Apr 1, 2004, 3:25:47 PM4/1/04
to
Am I correct in think that you can't re-assign a reference to a different
object? If so, what should happen here:

struct A
{
DoSomeThing();
};

A& GetNextA();

while (1)
{
A& a = GetNextA();

a.DoSomeThing();
}

Does reference 'a' only get assigned first time around the loop and,
thereafter, object 'a' gets assigned to the next 'A'... or is 'a' connected
to a different 'A' every time around the loop? What about this:

while (1)
{
{
A& a = GetNextA();

a.DoSomeThing();
}
}

Surely, 'a' would now be different every time around the loop (because the
scope of 'a' ends before looping?

On a related note, is it possible to prevent a reference to a class
instance? Similarly, is it possible to prevent the address of an instance
from being taken?

What I'm looking for is a way to implement a 'Reference<T>' class. In other
words, some kind of class like a smart-pointer except that the 'Reference'
is the only way to access the object to which it refers. I want to prevent
'address-of' and references and use the 'Reference' as a means to manage
object life-time.

Any insight or links to good articles will be very much appreciated.

Regards


Tim


Ron Natalie

unread,
Apr 1, 2004, 3:50:33 PM4/1/04
to

"Tim Clacy" <nosp...@nospamphaseone.nospamdk> wrote in message news:406c7acc$0$225$edfa...@dread11.news.tele.dk...

> while (1)
> {
> A& a = GetNextA();
>
> a.DoSomeThing();
> }
>

Since "a" is not declared static, it gets initalized everytime code passes through
the block.

> while (1)
> {
> {
> A& a = GetNextA();
>
> a.DoSomeThing();
> }
> }

The extra { } have no additional effect here.

> On a related note, is it possible to prevent a reference to a class
> instance? Similarly, is it possible to prevent the address of an instance
> from being taken?

You can't do anything to prevent a value from being bound to a reference.
You can make taking the address of it difficult, by overloading the unary
& operator for the class, but I'm not certain that would be a fool proof
way of disabling it entirely.

>
> What I'm looking for is a way to implement a 'Reference<T>' class. In other
> words, some kind of class like a smart-pointer except that the 'Reference'
> is the only way to access the object to which it refers. I want to prevent
> 'address-of' and references and use the 'Reference' as a means to manage
> object life-time.

I'm unclear of what you're really trying to accomplish, however provided you don't
specifically provide a way to do with it, a Reference<T> wouldn't be bindable to T&.
However such a class would have other problems. Specifically, you can't overload
operator (period). .

Pete Vidler

unread,
Apr 1, 2004, 3:52:17 PM4/1/04
to
Tim Clacy wrote:
> Am I correct in think that you can't re-assign a reference to a different
> object? If so, what should happen here:

Yes.

[snip]


> {
> A& a = GetNextA();
>
> a.DoSomeThing();
> }

The object "a" only exists within this scope. Once the scope is left it
should be destroyed. When the loop re-enters the scope a new object,
also called "a", will be created.

I suppose compiler optimisations might change this behaviour in some
unnoticeable way.

Note that I'm not certain about any of this. You could always try it and
see what your compiler does.

> Does reference 'a' only get assigned first time around the loop and,
> thereafter, object 'a' gets assigned to the next 'A'... or is 'a' connected
> to a different 'A' every time around the loop? What about this:
>
> while (1)
> {
> {
> A& a = GetNextA();
>
> a.DoSomeThing();
> }
> }

Call me crazy, but isn't that identical to the last bit of code? You're
just adding an extra (redundant) scope.

> Surely, 'a' would now be different every time around the loop (because the
> scope of 'a' ends before looping?

Yes, I'm pretty sure they are the same.

> On a related note, is it possible to prevent a reference to a class
> instance? Similarly, is it possible to prevent the address of an instance
> from being taken?
>
> What I'm looking for is a way to implement a 'Reference<T>' class. In other
> words, some kind of class like a smart-pointer except that the 'Reference'
> is the only way to access the object to which it refers. I want to prevent
> 'address-of' and references and use the 'Reference' as a means to manage
> object life-time.

I do this by writing public static "Create" methods in each class that
return a smart pointer to the new object. All constructors are
private/protected so there is no way of creating the object outside of
the static methods. Consequently there is no direct access to the object
itself (only through the smart pointer), so a reference or pointer to it
cannot be obtained (unless the smart pointer allows it).

Like this:

class SafeObject
{
public:
static MySmartPtr< SafeObject > Create();

private:
SafeObject() {}

// Probably don't need private copy-ctors or copy-assignment
// operators, because you can't access the object directly
// to use them with anyway.
};

Where "MySmartPtr" is your "Reference" class template. You will be able
to take a reference or pointer of MySmartPtr, but not of SafeObject
directly (to the best of my knowledge).

Hope that helps.

-- Pete

Tim Clacy

unread,
Apr 2, 2004, 7:19:24 AM4/2/04
to
Pete Vidler wrote:
> Tim Clacy wrote:
>> Am I correct in think that you can't re-assign a reference to a
>> different object? If so, what should happen here:
>
> Yes.
>
> [snip]
>> {
>> A& a = GetNextA();
>>
>> a.DoSomeThing();
>> }
>
> The object "a" only exists within this scope. Once the scope is left
> it should be destroyed. When the loop re-enters the scope a new
> object,
> also called "a", will be created.

Pete,

Hi. So when you loop, this is like leaving a scope then re-entering?

> I suppose compiler optimisations might change this behaviour in some
> unnoticeable way.
>
> Note that I'm not certain about any of this. You could always try it
> and
> see what your compiler does.
>
>> Does reference 'a' only get assigned first time around the loop and,
>> thereafter, object 'a' gets assigned to the next 'A'... or is 'a'
>> connected to a different 'A' every time around the loop? What about
>> this:
>>
>> while (1)
>> {
>> {
>> A& a = GetNextA();
>>
>> a.DoSomeThing();
>> }
>> }
>
> Call me crazy, but isn't that identical to the last bit of code?
> You're
> just adding an extra (redundant) scope.
>
>> Surely, 'a' would now be different every time around the loop
>> (because the scope of 'a' ends before looping?
>
> Yes, I'm pretty sure they are the same.

Yep, it sounds like they are the same. I wasn't (still not) entirely clear
about life-time of variables/references/objects inside a loop scope. If
variables/references/objects are destroyed and re-constructed every loop
cycle, then my second case is the same as the first.

Hmm, that's about where I am right now... but all we've done is replaced the
problem of controlling the object life-time with a problem of controlling
the smart-pointer life-time.

>
> -- Pete


Tim Clacy

unread,
Apr 2, 2004, 7:35:21 AM4/2/04
to
Ron Natalie wrote:
> "Tim Clacy" <nosp...@nospamphaseone.nospamdk> wrote in message
> news:406c7acc$0$225$edfa...@dread11.news.tele.dk...
>
>> while (1)
>> {
>> A& a = GetNextA();
>>
>> a.DoSomeThing();
>> }
>>
>
> Since "a" is not declared static, it gets initalized everytime code
> passes through
> the block.
>
>> while (1)
>> {
>> {
>> A& a = GetNextA();
>>
>> a.DoSomeThing();
>> }
>> }
>
> The extra { } have no additional effect here.
>
>> On a related note, is it possible to prevent a reference to a class
>> instance? Similarly, is it possible to prevent the address of an
>> instance
>> from being taken?
>
> You can't do anything to prevent a value from being bound to a
> reference.

Ron,

Hi. Doesn't this mean that there is no automatic way to manage object
life-time (because anyone can just connect a C++ reference to any object)?

> You can make taking the address of it difficult, by overloading the
> unary & operator for the class, but I'm not certain that would be a
> fool proof
> way of disabling it entirely.
>>
>> What I'm looking for is a way to implement a 'Reference<T>' class.
>> In other
>> words, some kind of class like a smart-pointer except that the
>> 'Reference'
>> is the only way to access the object to which it refers. I want to
>> prevent 'address-of' and references and use the 'Reference' as a
>> means to manage
>> object life-time.
>
> I'm unclear of what you're really trying to accomplish, however
> provided you don't
> specifically provide a way to do with it, a Reference<T> wouldn't be
> bindable to T&.
> However such a class would have other problems. Specifically, you
> can't overload
> operator (period). .

...hmm, so the long and the short of it is that if you don't mind using '->'
to access objects you can almost acheive automatic object life-time, but if
you want to use '.' you have to use C++ references, which are an
object-life-time management nightmare?

Regards


Tim


Pete Vidler

unread,
Apr 2, 2004, 7:42:03 AM4/2/04
to
Tim Clacy wrote:
[snip]

> Hi. So when you loop, this is like leaving a scope then re-entering?

Effectively, yes.

[snip]


>>Yes, I'm pretty sure they are the same.
>
> Yep, it sounds like they are the same. I wasn't (still not) entirely clear
> about life-time of variables/references/objects inside a loop scope. If
> variables/references/objects are destroyed and re-constructed every loop
> cycle, then my second case is the same as the first.

Of course, I'm not exactly certain about this. Consider the fact that,
in a "for( int i =... )" loop, the i variable is considered to be inside
the loop's scope. It doesn't get deleted and reconstructed each time,
though.

I'm just confusing myself now. In reality all this is rarely an issue.
If you need a variable in every loop cycle, declare it outside the loop.

[snip]


> Hmm, that's about where I am right now... but all we've done is replaced the
> problem of controlling the object life-time with a problem of controlling
> the smart-pointer life-time.

[snip]

Smart pointers are typically reference counted. If all you really want
is a smart pointer, check out boost::shared_ptr from www.boost.org. I
can highly recommend it (and the rest of that library).

As an aside about shifting the problem onto a separate class, this is a
common technique in C++. The answer to many problems seems to be adding
an extra layer of indirection (so I've heard).

-- Pete

Buster

unread,
Apr 2, 2004, 8:32:19 AM4/2/04
to
Pete Vidler wrote:

> Tim Clacy wrote:
>
> [snip]
>
>> Hi. So when you loop, this is like leaving a scope then re-entering?
>
> Effectively, yes.
>
> [snip]
>
>>> Yes, I'm pretty sure they are the same.
>>
>> Yep, it sounds like they are the same. I wasn't (still not) entirely
>> clear
>> about life-time of variables/references/objects inside a loop scope. If
>> variables/references/objects are destroyed and re-constructed every loop
>> cycle, then my second case is the same as the first.
>
> Of course, I'm not exactly certain about this. Consider the fact that,
> in a "for( int i =... )" loop, the i variable is considered to be inside
> the loop's scope. It doesn't get deleted and reconstructed each time,
> though.

There are two nested scopes associated with for loops: an outer scope
for any declaration-definition in the 'for' initializer, and an inner
scope for the loop body. The inner scope may or may not be marked
explicitly with braces but it's always there. The outer scope is entered
once at the beginning of the construct and left once after all
iterations are complete. The inner scope is entered and left on every
iteration.

For while loops, the scope of a declaration in the 'while' condition
contains the scope of the loop body and is entered and left once for
every iteration. It's less important here to make the 'two scopes'
distinction. The same is true of declarations in 'if' conditions.
('switch' too?)

You can depend on this absolutely. Optimization won't change the meaning
of your code. The one small snag is that there are compilers that use
obsolete rules for the scope of declarations in for, while and if
statements. Hopefully it's no longer necessary to think about that.

> [...]

Regards,
Buster.

Tim Clacy

unread,
Apr 2, 2004, 8:57:47 AM4/2/04
to

I've have perused Boost (some of the 15MB) and there's some awfully clever
stuff in there. However, what's to stop someone taking a C++ reference to a
smart-pointer (i.e. defeating the purpose)?

Tim Clacy

unread,
Apr 2, 2004, 9:00:59 AM4/2/04
to

Cheers.


Alf P. Steinbach

unread,
Apr 2, 2004, 9:01:26 AM4/2/04
to
* "Tim Clacy" <nosp...@nospamphaseone.nospamdk> schriebt:

> Hi. Doesn't this mean that there is no automatic way to manage object
> life-time (because anyone can just connect a C++ reference to any object)?

In theory yes. In practice no. Both because code that does that breaks
the contract, and because you _can_ (although no one does) make it
utterly impractical to obtain a direct reference.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Pete Vidler

unread,
Apr 2, 2004, 9:15:41 AM4/2/04
to
Tim Clacy wrote:
[snip]

> I've have perused Boost (some of the 15MB) and there's some awfully clever
> stuff in there. However, what's to stop someone taking a C++ reference to a
> smart-pointer (i.e. defeating the purpose)?
[snip]

Nothing prevents it. It just isn't a problem.

Unless you have a specific situation where it could be a problem?

-- Pete

Jeff Flinn

unread,
Apr 2, 2004, 9:45:52 AM4/2/04
to

"Tim Clacy" <nosp...@nospamphaseone.nospamdk> wrote in message
news:406d715c$0$283$edfa...@dread11.news.tele.dk...

> Pete Vidler wrote:
> > Tim Clacy wrote:
> > [snip]
> >> Hi. So when you loop, this is like leaving a scope then re-entering?
> >
> > Effectively, yes.
> >
> > [snip]

> > Smart pointers are typically reference counted. If all you really want


> > is a smart pointer, check out boost::shared_ptr from www.boost.org. I
> > can highly recommend it (and the rest of that library).
>
> I've have perused Boost (some of the 15MB) and there's some awfully clever
> stuff in there. However, what's to stop someone taking a C++ reference to
a
> smart-pointer (i.e. defeating the purpose)?

How? Can you show a case where it's an issue? A typical usage would be:

struct A
{
...

bool GotMilk()const{ return true; }
};

void somefunction( A& aRef )
{
bool lGood = aRef.GotMilk():
}

void SomeOtherFunction()
{
boost::shared_ptr<A> lAPtr( new A );

...

somefunction( *lAPtr ); // reference valid for the
// duration of somefunction
// indeed for this entire scope
...

} //

Jeff F


Tim Clacy

unread,
Apr 2, 2004, 10:23:31 AM4/2/04
to
Alf P. Steinbach wrote:
> * "Tim Clacy" <nosp...@nospamphaseone.nospamdk> schriebt:
>> Hi. Doesn't this mean that there is no automatic way to manage object
>> life-time (because anyone can just connect a C++ reference to any
>> object)?
>
> In theory yes. In practice no. Both because code that does that
> breaks the contract, and because you _can_ (although no one does)
> make it
> utterly impractical to obtain a direct reference.

Alf,

Hi. How can one make it impractical to obtain a direct reference to an
object; others are saying that you can't do that?


Tim


Tim Clacy

unread,
Apr 2, 2004, 10:38:54 AM4/2/04
to
Pete Vidler wrote:
> Tim Clacy wrote:
> [snip]
>> I've have perused Boost (some of the 15MB) and there's some awfully
>> clever stuff in there. However, what's to stop someone taking a C++
>> reference to a smart-pointer (i.e. defeating the purpose)?
> [snip]
>
> Nothing prevents it. It just isn't a problem.

...hmm, don't you think robust object life-time management is just about the
most important thing to get right to help ensure a robust, quality product?
My experience is that if something is fragile, sooner or later, it will
break... but perhaps I've just been unlucky?

Tim Clacy

unread,
Apr 2, 2004, 10:45:36 AM4/2/04
to

What if somefunction assigns a static or class member to that reference...
or copies it to another thread?

>
> } //
>
> Jeff F


Pete Vidler

unread,
Apr 2, 2004, 11:06:05 AM4/2/04
to
Tim Clacy wrote:
[snip]
>>Nothing prevents it. It just isn't a problem.
>
> ...hmm, don't you think robust object life-time management is just about the
> most important thing to get right to help ensure a robust, quality product?
> My experience is that if something is fragile, sooner or later, it will
> break... but perhaps I've just been unlucky?
[snip]

Yes, but using a smart pointer is just about as robust as it gets. You
still haven't explained how it isn't robust -- there's nothing wrong
with taking a reference to the smart pointer that I can see. So long as
you don't mess with raw pointers your app will be perfectly robust.

The only problem would be if you could assing a temporary object to a
reference, but I'm pretty sure the standard forbids it. You can assign
temporaries to const references, but then the lifetime of the temporary
is guaranteed to be at least as long as the lifetime of the const
reference (I believe).

-- Pete

Pete Vidler

unread,
Apr 2, 2004, 11:10:33 AM4/2/04
to
Tim Clacy wrote:
[snip]

> What if somefunction assigns a static or class member to that reference...
> or copies it to another thread?
[snip]

In the case of a programmer assigning static members to references, the
fool deserves everything he gets. You can protect programmers from
themselves only so far.

In the given example you cannot reassign a reference. It just isn't
legal C++. You can alter the object that the reference is of, in ways
determined by the interface of its class (providing it's a non-const
reference), but that's about it.

-- Pete

Tim Clacy

unread,
Apr 2, 2004, 11:34:49 AM4/2/04
to
"Pete Vidler" <pvi...@mailblocks.com> wrote in message
news:bagbc.504$iX5...@newsfe1-gui.server.ntli.net...

> Tim Clacy wrote:
> [snip]
> >>Nothing prevents it. It just isn't a problem.
> >
> > ...hmm, don't you think robust object life-time management is just about
the
> > most important thing to get right to help ensure a robust, quality
product?
> > My experience is that if something is fragile, sooner or later, it will
> > break... but perhaps I've just been unlucky?
> [snip]
>
> Yes, but using a smart pointer is just about as robust as it gets. You
> still haven't explained how it isn't robust -- there's nothing wrong
> with taking a reference to the smart pointer that I can see. So long as
> you don't mess with raw pointers your app will be perfectly robust.

I'm almost convinced... provided that it is possible to ensure that only the
smart pointer can do the creation of the object and that it's not possible
to 'new' smart pointers (so the life-time of the smart-pointer is under
control) and it's not possible to take the address of smart pointers. That
should all be acheivable shouldn't it?

I think I'll spend the weekend studying Boost's smart pointer.

Cheers

Alf P. Steinbach

unread,
Apr 2, 2004, 2:10:45 PM4/2/04
to
* "Tim Clacy" <nosp...@nospamphaseone.nospamdk> schriebt:
>
> How can one make it impractical to obtain a direct reference to an
> object

This was discussed in
<url:
http://www.google.com/groups?threadm=c0aur7%2414gog5%241%40ID-14036.news.uni-berlin.de>

Summary of proposed solutions in the context of preventing deletion via
a raw pointer obtained from a smart-pointer class:

Andrei Alexandrescu, Thomas Mang, Steve Dewhurst:
Let operator-> return a proxy (and Andrei, of course, further proposed
using a recursive template to generate a proxy to proxy to proxy..., say
to 100 levels, to really make it hard for client code to get the address).

Paavo Helde:
If you own the implementation of the class A that the smart pointer
encapsulates, let its destructor be protected and let the smart
pointer's operator-> return a pointer to a derived class instance.

Niklas Borson:
Let the smart pointer be a wrapper class with one wrapper function
for each function of the wrapped class, instead of using operator->.

Pete Vidler

unread,
Apr 2, 2004, 3:13:14 PM4/2/04
to
Tim Clacy wrote:
[snip]

> I'm almost convinced... provided that it is possible to ensure that only the
> smart pointer can do the creation of the object and that it's not possible
> to 'new' smart pointers (so the life-time of the smart-pointer is under
> control) and it's not possible to take the address of smart pointers. That
> should all be acheivable shouldn't it?
[snip]

The basics are straight from the FAQ:

class SafeClass
{
public:
typedef boost::shared_ptr< SafeClass > Ptr;

// Might need a static_cast here, I don't remember exactly.
Ptr Create() { return new SafeClass; }

private:
SafeClass() { ... }
};

// This should be the only way to create a SafeClass object:
SafeClass::Ptr safeClass1 = SafeClass::Create();

This meets my top two criteria -- safe and readable.

In the thread "Base class method that returns a pointer to a derived
class?" on this newsgroup I've detailed a technique for extending this
to a hierarchy (from Maxim Yegorushkin on comp.lang.c++.moderated).

-- Pete

Pete Vidler

unread,
Apr 3, 2004, 7:05:49 AM4/3/04
to
Pete Vidler wrote:
[snip]

> class SafeClass
> {
> public:
> typedef boost::shared_ptr< SafeClass > Ptr;
>
> // Might need a static_cast here, I don't remember exactly.
> Ptr Create() { return new SafeClass; }

That Create method was meant to be static, obviously.

> private:
> SafeClass() { ... }
> };
>
> // This should be the only way to create a SafeClass object:
> SafeClass::Ptr safeClass1 = SafeClass::Create();

-- Pete

Tim

unread,
Apr 4, 2004, 1:01:30 PM4/4/04
to
"Pete Vidler" <pvi...@mailblocks.com> wrote in message
news:gMxbc.74$6u1...@newsfe5-gui.server.ntli.net...

Don't we have an even worse issue here; what if someone makes a reference to
the returned temporary instead of copying it:

SafeClass::Ptr& safeClass1 = SafeClass::Create();

Now the instance of SafeClass is a bona-fide memory leak.

Tim

unread,
Apr 4, 2004, 1:06:25 PM4/4/04
to

"Pete Vidler" <pvi...@mailblocks.com> wrote in message
news:bfgbc.204$%m5.81@newsfe1-win...

But the big problem, surely, is that when the reference goes out of scope,
the destructor of the object to which it refers is not called and we have a
lingering object. It seems much easier to make reference to instances than
to ensure that those instances are cleaned-up when its referees expire.


Pete Vidler

unread,
Apr 4, 2004, 1:26:18 PM4/4/04
to
Tim wrote:
[snip]

> Don't we have an even worse issue here; what if someone makes a reference to
> the returned temporary instead of copying it:
>
> SafeClass::Ptr& safeClass1 = SafeClass::Create();
>
> Now the instance of SafeClass is a bona-fide memory leak.
[snip]

No it isn't. The standard forbids assigning a temporary to a non-const
reference. It won't even compile (with a half decent compiler).

If you used a const-reference, the object is guaranteed to survive at
least as long as the const-reference.

Besides, that isn't a memory leak even if it was allowed. The smart
pointer will always free the memory, it's just that the reference would
then be invalid. But it can't happen, so it doesn't matter.

-- Pete

Old Wolf

unread,
Apr 4, 2004, 10:03:37 PM4/4/04
to
"Tim Clacy" wrote:
> Pete Vidler wrote:
> > Tim Clacy wrote:
> >> I've have perused Boost (some of the 15MB) and there's some awfully
> >> clever stuff in there. However, what's to stop someone taking a C++
> >> reference to a smart-pointer (i.e. defeating the purpose)?
> >
> > Nothing prevents it. It just isn't a problem.
>
> ...hmm, don't you think robust object life-time management is just about the
> most important thing to get right to help ensure a robust, quality product?

No! I'm firmly on the Murphy side (and you seem to be on the
Machiavelli side): I think the idea is to make sure the users of your
library don't screw up accidentally, but not to try and prevent them
screwing up on purpose. No matter what measures you take, there
will always be a way to get around them if someone is hell-bent on
doing so.

> My experience is that if something is fragile, sooner or later, it will
> break... but perhaps I've just been unlucky?

What does 'pointer' have to do with 'fragile' ?
If someone creates and deletes your objects, good on them. You
don't have to try and prevent people from forgetting to free a
pointer, for example.
IMHO, adding more complexity to your class to guard against nasty
people, is just making it more fragile.

0 new messages