Topic: Re-initializing of references
Author: thp@cs.ucr.edu
Date: Thu, 17 Jun 2004 17:16:17 +0000 (UTC) Raw View
thp@cs.ucr.edu wrote:
[...]
: IIUC, the occurrences of the name "c" in lines 4 and 7 of the body of
: main() are in the same scope and, per some clause of the Standard
: (which I don't have here), all occurrences of a given name that are in
: the same scope refer to the same entity. If my understanding of that
: clause is correct, then the Standard contains an apparent
: contradiction. But, so far as I can tell, the behavior is well-define
: and identical either way.
The clause to which I referred is 3.3#4.
Also (IIUC) the two cases would not be equally well defined, if c.data
were a const pointer instead of a reference. Specifically, if the
reincarnated c is a continuation of the old c, then the const c.data
gets modified and subsequent behavior is undefined. If, however, the
reincarnated c is a new and distinct object at the location of the old
c, then there has been no "modification" to a const and the subsequent
behavior is well defined. That means that this "apparent
contradiction" in the Standard has semantic consequences and ought to
be fixed.
Having the subsequent behavior defined (which it is either way when
c.data is a reference) seems likely to astonish both readers of the
program and implementers of the languages. So that would be a
separate defect, which (IIRC) already has a report.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 17 Jun 2004 17:16:27 +0000 (UTC) Raw View
thp@cs.ucr.edu wrote in message news:<cap4ho$t2n$1@glue.ucr.edu>...
> James Kuyper <kuyper@wizard.net> wrote:
> [...]
> : The storage duration of automatically allocated objects is determined
> : by entering and leaving the scopes in which their names are defined.
> : Storage duration is one of the things that can determin an object's
> : lifetime. However, there are other ways of ending and starting an
> : automatically allocated object's lifetime: explicit destructor calls
> : end an object's lifetime, and inplace construction starts the lifetime
> : of a new object occupying the same space as the original(3.8p1,4).
> : Pointers and references to and into the old object will point at the
> : new object as well (3.8p7), but it is a new object.
>
> Repeating the example:
>
> #include<iostream>
> #include<new>
>
> template<typename T> struct ref {
> T &data;
> ref(T &x) : data(x) {}
> };
>
> int main(void) {
> int a,b;
> ref<int> c(a);
> std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
> c.~ref(); // superfluous call, just ensures number of
> // destructor calls equals number of constructor calls
> new(&c) ref<int>(b);
> std::cout << (&c.data==&b) << std::endl;
> return 0;
> }
> /* Output:
> true
> true
> */
>
> IIUC, the occurrences of the name "c" in lines 4 and 7 of the body of
> main() are in the same scope and, per some clause of the Standard
> (which I don't have here), all occurrences of a given name that are in
> the same scope refer to the same entity.
3.3p4 comes closest:
"Given a set of declarations in a single declarative region, each of
which specifies the same unqualified name,
-- they shall all refer to the same entity, or ..."
The "or" clauses don't apply when the names in question describes an
object, so the "same entity" clause must apply.
>... If my understanding of that
> clause is correct, then the Standard contains an apparent
> contradiction. But, so far as I can tell, the behavior is well-define
> and identical either way.
Since the only applicable meaning of "entity" from 3p3 in this context
is "object", and considering the case where the applicable "set of
declarations" has only one member, this does seem in conflict with the
object lifetime rules.
Perhaps the intent is that when an explicit destructor call ends the
lifetime of an object, and is followed by in-place constructor call
that starts a new lifetime, that it's still considered to be the same
object?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: thp@cs.ucr.edu
Date: Fri, 18 Jun 2004 19:55:20 +0000 (UTC) Raw View
James Kuyper <kuyper@wizard.net> wrote:
: thp@cs.ucr.edu wrote in message news:<cap4ho$t2n$1@glue.ucr.edu>...
[...]
:> IIUC, the occurrences of the name "c" in lines 4 and 7 of the body of
:> main() are in the same scope and, per some clause of the Standard
:> (which I don't have here), all occurrences of a given name that are in
:> the same scope refer to the same entity.
:
: 3.3p4 comes closest:
: "Given a set of declarations in a single declarative region, each of
: which specifies the same unqualified name,
:
: -- they shall all refer to the same entity, or ..."
:
: The "or" clauses don't apply when the names in question describes an
: object, so the "same entity" clause must apply.
:
:>... If my understanding of that
:> clause is correct, then the Standard contains an apparent
:> contradiction. But, so far as I can tell, the behavior is well-define
:> and identical either way.
:
: Since the only applicable meaning of "entity" from 3p3 in this context
: is "object", and considering the case where the applicable "set of
: declarations" has only one member, this does seem in conflict with the
: object lifetime rules.
:
: Perhaps the intent is that when an explicit destructor call ends the
: lifetime of an object, and is followed by in-place constructor call
: that starts a new lifetime, that it's still considered to be the same
: object?
There's obviously a conflict. Initially, I thought it was only a
semantically irrelevant conflict among the metaphysical metaphors of
the metalanguage. ;-) I'd like to argue that an extension of the
as-if rule makes this a moot point, i.e., even if the before and after
versions of c.data are different objects they behave as if they were
the same. But, as I noted in my self-followup, that's not so when
c.data is a const pointer rather than a reference. And, unfortunately,
the obvious solutions destroy the elegant simplicity of the
one-denotation-per-scope rule.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: thp@cs.ucr.edu
Date: Wed, 16 Jun 2004 15:48:05 +0000 (UTC) Raw View
James Kuyper <kuyper@wizard.net> wrote:
[...]
: The storage duration of automatically allocated objects is determined
: by entering and leaving the scopes in which their names are defined.
: Storage duration is one of the things that can determin an object's
: lifetime. However, there are other ways of ending and starting an
: automatically allocated object's lifetime: explicit destructor calls
: end an object's lifetime, and inplace construction starts the lifetime
: of a new object occupying the same space as the original(3.8p1,4).
: Pointers and references to and into the old object will point at the
: new object as well (3.8p7), but it is a new object.
Repeating the example:
#include<iostream>
#include<new>
template<typename T> struct ref {
T &data;
ref(T &x) : data(x) {}
};
int main(void) {
int a,b;
ref<int> c(a);
std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
c.~ref(); // superfluous call, just ensures number of
// destructor calls equals number of constructor calls
new(&c) ref<int>(b);
std::cout << (&c.data==&b) << std::endl;
return 0;
}
/* Output:
true
true
*/
IIUC, the occurrences of the name "c" in lines 4 and 7 of the body of
main() are in the same scope and, per some clause of the Standard
(which I don't have here), all occurrences of a given name that are in
the same scope refer to the same entity. If my understanding of that
clause is correct, then the Standard contains an apparent
contradiction. But, so far as I can tell, the behavior is well-define
and identical either way.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Mon, 14 Jun 2004 17:52:50 +0000 (UTC) Raw View
thp@cs.ucr.edu wrote in message news:<ca9qg9$q09$1@glue.ucr.edu>...
> James Kuyper <kuyper@wizard.net> wrote:
> : kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0404152038.559c36ab@posting.google.com>...
> :> It is normaly said that one cannot change what a reference refers to.
> :> However, it seems that this is possible provided the reference is a
> :> member of a
> :> class/struct. For example,
> :>
> :> #include<iostream>
> :> #include<new>
> :>
> :> template<typename T> struct ref
> :> {
> :> T &data;
> :> ref(T &x) : data(x) {}
> :> };
> :>
> :> int main(void)
> :> {
> :> int a,b;
> :> ref<int> c(a);
> :> std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
> :> c.~ref(); //superfluous call, just ensures number of destructor calls
> :> equals number of constructor
> :> calls
> :> new(&c) ref<int>(b);
> :> std::cout<<(&c.data==&b)<<std::endl;
> :> return 0;
> :>
> :> }
> :> /* Output:
> :> true
> :> true
> :> */
> :>
> :> This shows that c.data refers to a first and then to b. The same
> :> technique can be used to change the value of const data members. Is
> :> this a well-formed
> :> program? If yes, does this mean it is possible to change the target of
> :> a member reference or the value of a member constant.
> :
> : Not quite. The second c.data refers to a different reference than the
> : first one. The second reference lives in the same memory location that
> : used to be occupied by the previous one, and can be accessed using the
> : same syntax. However, the first one ceased to exist when the
> : destructor was called, and the second one came into existence when you
> : performed the in-place construction. This is in principle no different
> : from the following:
> :
> : for(int i=0; i<n; i++)
> : {
> : int &ref=array[i];
> : // Use ref somehow.
> : }
> :
> : Each time you enter the body of that loop, a new reference named 'ref'
> : is created, used, and destroyed, and there's a pretty good chance that
> : it might be created in the same memory location each time (depending
> : upon how it's initialized - in some context a reference is internally
> : implemented as a pointer, in other contexts no actual storage space is
> : needed). That doesn't mean that the references has been
> : re-initialized. Each pass through the loop it counts as a different
> : reference from the previous pass.
>
> Please excuse me for comining late.
>
> In your example, the scope has been exited and reentered. In the OP's
> example, however, we never leave the scope and thus (IIUC) the name
> "c" refers to the same object both before and after c's reincarnation.
The storage duration of automatically allocated objects is determined
by entering and leaving the scopes in which their names are defined.
Storage duration is one of the things that can determin an object's
lifetime. However, there are other ways of ending and starting an
automatically allocated object's lifetime: explicit destructor calls
end an object's lifetime, and inplace construction starts the lifetime
of a new object occupying the same space as the original(3.8p1,4).
Pointers and references to and into the old object will point at the
new object as well (3.8p7), but it is a new object.
In any event, the key issue is not whether c is the same object before
and after those lines of code. What matters is whether c.data refers
to the same object before and after. It does not.
..
> As I've said before, IMHO, the Standard would be more coherent if it
> viewed references as const objects. Then (IIUC) this obscure
> reseating would invoke undefined behavior, as does any modification
> other of a const object.
This same technique allows re-setting the value of const member
objects.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: thp@cs.ucr.edu
Date: Thu, 10 Jun 2004 17:45:26 +0000 (UTC) Raw View
James Kuyper <kuyper@wizard.net> wrote:
: kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0404152038.559c36ab@posting.google.com>...
:> It is normaly said that one cannot change what a reference refers to.
:> However, it seems that this is possible provided the reference is a
:> member of a
:> class/struct. For example,
:>
:> #include<iostream>
:> #include<new>
:>
:> template<typename T> struct ref
:> {
:> T &data;
:> ref(T &x) : data(x) {}
:> };
:>
:> int main(void)
:> {
:> int a,b;
:> ref<int> c(a);
:> std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
:> c.~ref(); //superfluous call, just ensures number of destructor calls
:> equals number of constructor
:> calls
:> new(&c) ref<int>(b);
:> std::cout<<(&c.data==&b)<<std::endl;
:> return 0;
:>
:> }
:> /* Output:
:> true
:> true
:> */
:>
:> This shows that c.data refers to a first and then to b. The same
:> technique can be used to change the value of const data members. Is
:> this a well-formed
:> program? If yes, does this mean it is possible to change the target of
:> a member reference or the value of a member constant.
:
: Not quite. The second c.data refers to a different reference than the
: first one. The second reference lives in the same memory location that
: used to be occupied by the previous one, and can be accessed using the
: same syntax. However, the first one ceased to exist when the
: destructor was called, and the second one came into existence when you
: performed the in-place construction. This is in principle no different
: from the following:
:
: for(int i=0; i<n; i++)
: {
: int &ref=array[i];
: // Use ref somehow.
: }
:
: Each time you enter the body of that loop, a new reference named 'ref'
: is created, used, and destroyed, and there's a pretty good chance that
: it might be created in the same memory location each time (depending
: upon how it's initialized - in some context a reference is internally
: implemented as a pointer, in other contexts no actual storage space is
: needed). That doesn't mean that the references has been
: re-initialized. Each pass through the loop it counts as a different
: reference from the previous pass.
Please excuse me for comining late.
In your example, the scope has been exited and reentered. In the OP's
example, however, we never leave the scope and thus (IIUC) the name
"c" refers to the same object both before and after c's reincarnation.
(Granted, there are parts of the Standard that support the
different-objects view as well.)
The question of whether we are talking about distinct objects or the
same object is something of a moot point, a metalanguage distinction
without a semantic difference. But, whichever view one takes, this
example raises the not-so-moot language-design question of what one
should be able to assume about the states of references following
calls to independently compiled functions -- for example, the
reincarnation of c could occur in a separately compiled functions to
which c gets passed by-pointer and/or by-reference. Following such a
call both the reader of the code and the implementer would be inclined
to think that c still refers to the same object and that it's
reference members have not been reseated.
As I've said before, IMHO, the Standard would be more coherent if it
viewed references as const objects. Then (IIUC) this obscure
reseating would invoke undefined behavior, as does any modification
other of a const object.
Tom Payne
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kprateek88@yahoo.com (Prateek R Karandikar)
Date: Fri, 16 Apr 2004 05:22:32 +0000 (UTC) Raw View
It is normaly said that one cannot change what a reference refers to.
However, it seems that this is possible provided the reference is a
member of a
class/struct. For example,
#include<iostream>
#include<new>
template<typename T> struct ref
{
T &data;
ref(T &x) : data(x) {}
};
int main(void)
{
int a,b;
ref<int> c(a);
std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
c.~ref(); //superfluous call, just ensures number of destructor calls
equals number of constructor
calls
new(&c) ref<int>(b);
std::cout<<(&c.data==&b)<<std::endl;
return 0;
}
/* Output:
true
true
*/
This shows that c.data refers to a first and then to b. The same
technique can be used to change the value of const data members. Is
this a well-formed
program? If yes, does this mean it is possible to change the target of
a member reference or the value of a member constant.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Fri, 16 Apr 2004 15:29:15 +0000 (UTC) Raw View
kprateek88@yahoo.com (Prateek R Karandikar) wrote in message news:<607f883e.0404152038.559c36ab@posting.google.com>...
> It is normaly said that one cannot change what a reference refers to.
> However, it seems that this is possible provided the reference is a
> member of a
> class/struct. For example,
>
> #include<iostream>
> #include<new>
>
> template<typename T> struct ref
> {
> T &data;
> ref(T &x) : data(x) {}
> };
>
> int main(void)
> {
> int a,b;
> ref<int> c(a);
> std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
> c.~ref(); //superfluous call, just ensures number of destructor calls
> equals number of constructor
> calls
> new(&c) ref<int>(b);
> std::cout<<(&c.data==&b)<<std::endl;
> return 0;
>
> }
> /* Output:
> true
> true
> */
>
> This shows that c.data refers to a first and then to b. The same
> technique can be used to change the value of const data members. Is
> this a well-formed
> program? If yes, does this mean it is possible to change the target of
> a member reference or the value of a member constant.
Not quite. The second c.data refers to a different reference than the
first one. The second reference lives in the same memory location that
used to be occupied by the previous one, and can be accessed using the
same syntax. However, the first one ceased to exist when the
destructor was called, and the second one came into existence when you
performed the in-place construction. This is in principle no different
from the following:
for(int i=0; i<n; i++)
{
int &ref=array[i];
// Use ref somehow.
}
Each time you enter the body of that loop, a new reference named 'ref'
is created, used, and destroyed, and there's a pretty good chance that
it might be created in the same memory location each time (depending
upon how it's initialized - in some context a reference is internally
implemented as a pointer, in other contexts no actual storage space is
needed). That doesn't mean that the references has been
re-initialized. Each pass through the loop it counts as a different
reference from the previous pass.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Fri, 16 Apr 2004 15:33:01 +0000 (UTC) Raw View
kprateek88@yahoo.com (Prateek R Karandikar) writes:
> It is normaly said that one cannot change what a reference refers to.
> However, it seems that this is possible provided the reference is a
> member of a
> class/struct. For example,
>
> #include<iostream>
> #include<new>
>
> template<typename T> struct ref
> {
> T &data;
> ref(T &x) : data(x) {}
> };
>
> int main(void)
> {
> int a,b;
> ref<int> c(a);
> std::cout<<std::boolalpha<<(&c.data==&a)<<std::endl;
> c.~ref(); //superfluous call, just ensures number of destructor calls
> equals number of constructor
> calls
> new(&c) ref<int>(b);
> std::cout<<(&c.data==&b)<<std::endl;
> return 0;
>
> }
> /* Output:
> true
> true
> */
>
> This shows that c.data refers to a first and then to b. The same
> technique can be used to change the value of const data members. Is
> this a well-formed
> program? If yes, does this mean it is possible to change the target of
> a member reference or the value of a member constant.
Doesn't the resolution of DR 89:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#89
which was included in TC1 make this code ill-formed?
Now the 3rd bullet of 3.8/7 says:
# the type of the original object is not const-qualified, and, if a
# class type, does not contain any non-static data member whose
# type is const-qualified or a reference type, and
So I think your example is undefined.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: hyrosen@mail.com (Hyman Rosen)
Date: Fri, 16 Apr 2004 15:33:18 +0000 (UTC) Raw View
Prateek R Karandikar wrote:
> If yes, does this mean it is possible to change the target of
> a member reference or the value of a member constant.
While the difference might be only philosophical, you have not
changed a member. You have created an entire new object in the
space of the old one, and that new object has the different
member.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]