|
Gatik,
I would like to retract my previously posted disagreement with you. Please accept my apology, as I re-inspected the binaries, and found that you are right: references are indeed automatically dereferenced const pointers.
Reference variable do indeed possess memory cells, just like constant pointers. The only difference between them is that I see no way to access the actual memory address of the reference variable via the language itself, i.e. through any C/C++ semantic device such as &, *, &*, etc.
It's almost always good to learn something new !
-Ilya
|
|
|
|
|
Hi Ilya,
I agree, Healthy exchange of arguments always leads to good conclusion(s). Thanks ..
Regards
Gatik
|
|
|
|
|
So let me get this straight. You claim that '6 out of 10 people will say references are alias', yet you cannot be bothered to define what an alias is, when asked (leaving aside the dubiousness of your '6 out of 10' claim). You claim not to care what aliases are, yet you make a big deal in your article about aliases, and that references are not aliases. Strange. You have introduced a term that is not defined by the Standard, and then proceed to make all kinds of claims about developers beliefs. Please define what an alias is, and then we can talk about whether references are aliases.
To reiterate, the Standard says two things about references -- that they are the names of objects, and that they may or may not take up space (you have read the Standard, haven't you?). Beyond that, it doesn't say anyting about implementation, since reference is a semantic concept. You claim that they always take up space ("there is no way you can have an alias in binary without occupying space"), and that is incorrect. If you force them to take up space, as when including them in a class, then sure. But when you use them as with parameter passing, then there is no need for them to take up any memory space at all. They may, for example be passed to a function in a register, and never make it to a memory location, depending on the underlying hardware architecture, and the cleverness of the compiler.
I think that it's a good thing to try to understand what goes on 'under the hood', but again, not everyone actually needs that information. You do, with the environment that you use, but many Windows programmers, for example, who are library clients (and not library designers) do not.
Again, I repeat: a reference is not a const pointer, although it may be implemented by an underlying mechanism that behaves like one. Even if it were, it would be no guarantee that it exists in memory, much like the fact that there is no guarantee that any constant that you use actually exists in memory.
I also believe that you are incorrect about my etiquette here. I read your article thinking that that I would gain some insight into references. I did not. Instead, I find an article that I found extremely confusing and unhelpful, due to introduction of undefined concepts, over-generalization from one particular implementation to all computers, and claims that go directly against what the Standard says, and and claims against what my experience tells me. It doesn't matter whether I pay for this article or not -- open forum etiquette allows me to question your claims, and ask that you back them up. Spreading confusion about C++ concepts does not do service to the audience of worldwide developers.
Jeff
|
|
|
|
|
Hi jef,
I can buy your arguments only when if you can proof that compilers implements the references in any way, other than const pointers.
For your claim that in case of functions it might go into registers. This can be the case for simple variable also for efficiency reasons. Try to dig into assemble codes generated.
Finally, Standards may also not ask you how to implement virtual table in the memory but more or less it is done in a same way by most of the compilers (you can’t argue till you get proper functionality).
And finally aging I am sorry but I found your statement
Spreading confusion about C++ concepts does not do service to the audience of worldwide developers.
VERY outrageous. if you can prove that I am spreading confusion about C++ and audience can support that. I will withdraw this article very next day along with my written apology for this.
Regards
Gatik
|
|
|
|
|
Gatik G wrote: I can buy your arguments only when if you can proof that compilers implements the references in any way, other than const pointers.
For your claim that in case of functions it might go into registers. This can be the case for simple variable also for efficiency reasons. Try to dig into assemble codes generated.
I'm not quite sure that I understand -- are you asking me to provide you with examples of when references may not take up memory? Here's one that I found:
int array[10] = {0};
int& ri = array[3];
ri = 4;
It should be fairly straightforward for a compiler to optimize away the existence of the reference variable 'ri', and do the assignment directly to the appropriate array member. The compiler that I am using (Microsoft C/C++ 12/VS2003) generated the single 8086 assembly instruction for the assignment:
mov DWORD PTR _array$[esp+84], 4
No use of the variable 'ri', and it takes up no space. QED.
Further, a reference to a static object can generally be optimized away (or at least into machine code offsets). References used in functions that are inlined may be optimized into register-only values. Yes, I could post examples of these, but what's the point? I just showed one case where a reference doesn't take up any space.
Gatik G wrote: Finally, Standards may also not ask you how to implement virtual table in the memory but more or less it is done in a same way by most of the compilers (you can’t argue till you get proper functionality).
Whatever this means, it has nothing to do with references.
Gatik G wrote: if you can prove that I am spreading confusion about C++ and audience can support that. I will withdraw this article very next day along with my written apology for this.
It's my opinion that your article is confusing, because it lacks clarity with respect to C++ concepts, and makes incorrect assertions about references. Of course, since it's my opinion, it is not provable. But let me try to explain. From your article:
Gatik G wrote: I choose to write about the references in C++ because I feel most of the people are having misconception about the references and I have got this feeling because I took many C++ interviews and I seldom get correct answers about references in C++.
So what are the questions you've asked about references, and what are the answers that you get that are so incorrect and so misconceived?
By the way, one of the interview questions that I ask is: What's the difference between a pointer and a reference? If the candidate told me that they are identical, then I would have a big problem recommending that we hire them.
Gatik G wrote: What is meant by references in C++? A reference is generally thought of an aliasing of the variable it refers to. I hate the definition of references being and Alias of a variable in C++. In this article I will try to explain that there is nothing known as aliasing in C++.
Here, you begin by asking a question about the nature of references, then you introduce the notion of aliasing, that you somehow dislike. For the third time, what do you mean by aliasing, with respect to references? And then why do you claim that there is no such thing as aliasing in C++? As I read the Standard, there is no official notion of aliasing in C++, but I don't think that's what you mean. You could clarify by defining what you mean by aliasing. By leaving such an important concept (to the stated purpose of your article) undefined, you create confusion.
Gatik G wrote: Background
Both in C and in C++ there are only two ways by which a variable can be accessed, passes, or retrieved. The two ways are
1. Accessing/passing variable by value.
2. Accessing/Passing variable by address. In this case pointers will come into picture.
There is no 3rd way of Accessing/Passing variable. A reference variable is just another pointer variable which will take its own space in memory. The most important thing about the references is that its a type of pointer which gets automatically dereferenced (by compiler..). Hard to believe? Let see....
Why this strange excursion into accessing/passing variables? Why not just go to the Standard for the definition? It's very simple, and quite clear: "A reference can be thought of as the name of an object". Nowhere does it say that references are pointers; indeed, pointers are described in a separate section.
Gatik G wrote: References are nothing but constant pointer in C++. A Statement int &i = j; will be converted by compiler to int *const i = &j; i.e References are nothing but constant pointers. They need initialization because constants must be initialized and since the pointer is constant they can't point to anything else. Lets take the same example of references in C++ and this time we will use the syntax what compiler uses when it sees references.
References are not constant pointers. A common implementation of references is indeed by using pointers, but the standard does require that. Moreover, the compiler does not convert the statement int &i = j; into int *const i = &j;. This is nonsensical. Don't believe me? Try this code:
double d;<br />
double& rd = d;<br />
cout << "size of d = " << sizeof d << " size of rd = " << sizeof rd << endl;
If rd were converted by the compiler into a pointer, then what would you expect its size to be? Moreover, references cannot be null, while pointers can be null. You cannot have a reference to void, but you vertainly can have a pointer to void. You can't even have an array of references. A reference is not a pointer, period. There is no such rule as you cite; it is not like the rule "the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2))", which is in the Standard. You made your rule up.
Gatik G wrote: We can see this by checking the size of the class which is having only reference variables. The example below proofs that a C++ reference is not an Alias and takes its own space into the memory.
We have also seen by my examples above that a reference does not actually need to take up memory space. And by the way, this accords with what the Standard says. And again, what is an alias?
So, by my reckoning, your article introduces a concept, aliasing, that is never defined; claims that many people believe that references are aliases (if true, why is that a bad thing?), complains that that that belief is incorrect, and then goes on to make claims about references that are unsupported both by the Standard and by at least one actual implementation. And then forgets to prove that aliases don't exist in C++. It proves nothing about references except that they can take up memory space (if you've read the Standard's description, then that should come as no surprise), and I'm sorry, but in my opinion, that's confusing and unhelpful.
My suggestion: if you wish to describe why a reference might take up memory space, then you should begin by citing the definition from the Standard and that the Standard says that a reference might take up space. Contrast it against when a reference might not take up space (now that you know that they need not). Explain how a compiler might implement a reference as a pointer, sure, but don't claim that a reference is a pointer. And forget about the concept of aliasing, at least until you define it, and why it matters to a reference's size.
I'm sorry; you get points for trying to be helpful in this forum. But that's not enough if the material you provide isn't clear and correct.
regards,
Jeff
|
|
|
|
|
Hi Jeff,
jefito wrote: nt array[10] = {0}; // simple array
int& ri = array[3]; // reference to array member
ri = 4; // change array member through reference
It should be fairly straightforward for a compiler to optimize away the existence of the reference variable 'ri', and do the assignment directly to the appropriate array member. The compiler that I am using (Microsoft C/C++ 12/VS2003) generated the single 8086 assembly instruction for the assignment:
mov DWORD PTR _array$[esp+84], 4
No use of the variable 'ri', and it takes up no space. QED
Maybe with your compiler and on your system. On my system (I'm using PowerPC Linux natively running on a G4, compiling my code with gcc 4.1), the outcome is different. The code:
void testfunc1()
{
int array[10] = {0}; // simple array
int& ri = array[3]; // reference to array member
ri = 4; // change array member through reference
}
gets compiled into:
_Z9testfunc1v:
.LFB1489:
stwu 1,-80(1)
.LCFI6:
mflr 0
.LCFI7:
stw 31,76(1)
.LCFI8:
stw 0,84(1)
.LCFI9:
mr 31,1
.LCFI10:
addi 0,31,12
li 9,40
mr 3,0
li 4,0
mr 5,9
bl memset
addi 9,31,12
addi 0,9,12
stw 0,8(31)
lwz 9,8(31)
li 0,4
stw 0,0(9)
lwz 11,0(1)
lwz 0,4(11)
mtlr 0
lwz 31,-4(11)
mr 1,11
blr
The code:
void testfunc2()
{
int array[10] = {0}; // simple array
array[3] = 4;
}
gets compiled into:
_Z9testfunc2v:
.LFB1490:
stwu 1,-80(1)
.LCFI11:
mflr 0
.LCFI12:
stw 31,76(1)
.LCFI13:
stw 0,84(1)
.LCFI14:
mr 31,1
.LCFI15:
addi 0,31,8
li 9,40
mr 3,0
li 4,0
mr 5,9
bl memset
li 0,4
stw 0,20(31)
lwz 11,0(1)
lwz 0,4(11)
mtlr 0
lwz 31,-4(11)
mr 1,11
blr
The code:
void testfunc3()
{
int array[10] = {0}; // simple array
int *const rp = &array[3]; // pointer to array member
*rp = 4; // change array member through const pointer
}
gets compiled into:
_Z9testfunc3v:
.LFB1491:
stwu 1,-80(1)
.LCFI16:
mflr 0
.LCFI17:
stw 31,76(1)
.LCFI18:
stw 0,84(1)
.LCFI19:
mr 31,1
.LCFI20:
addi 0,31,12
li 9,40
mr 3,0
li 4,0
mr 5,9
bl memset
addi 9,31,12
addi 0,9,12
stw 0,8(31)
lwz 9,8(31)
li 0,4
stw 0,0(9)
lwz 11,0(1)
lwz 0,4(11)
mtlr 0
lwz 31,-4(11)
mr 1,11
blr
Now, Jeff, notice that the codes generated for testfunc1 and testfunc3 are the same. testfunc2, on the other hand, gets a compiled into a different set of instructions. QED (FOR GCC on PowerPC).
By the way, are you sure that your wonderful Microsoft compiler didn't simply optimize the reference variable away? Try my version of your code that uses a const pointer instead of a reference (in testfunc3) and see what code the compiler will produce. If it produces the same assembly code as before, please try to turn-off the optimizer and then see what happens.
I hope that Gatik will forgive me, if I interpret him that by saying that "many people think of a reference variable as an alias" he meant to say this:
Many people think that a declared&defined reference variable is interpreted by the compiler to be just another name for the original variable.
And that's as simple as that. Gatik then proceeded to say that the above notion is generally not true. What's your problem with that?
Gatik *does not say* that references are the same as const pointers. What he says is that they are the automatically dereferenced versions thereof. That's why in your code snippet:
jefito wrote: double d;
double& rd = d;
cout << "size of d = " << sizeof d << " size of rd = " << sizeof rd << endl;
You get "8."
Another interesting example is taking the address of "rd." You will get the same number as that for "d."
That's why I view reference variable as const pointers with a twist. I don't know how the Microsoft compiler implements them, but in my case: if a reference variable doesn't occupy any space, that means that, if a corresponding const pointer is defined instead, it, too, will be optimized away.
I hope I didn't introduce any more confusion than is already there!! In fact, I also hope that I clarified some.
I do, however, agree with you on this: maybe the author should indeed be more precise, elaborate, and rigorous when explaining the relation between references and const pointers. It is a site that often gets visited by knowledgeable folks, after all.
Regards,
Ilya
|
|
|
|
|
Ilya Lipovsky wrote: Another interesting example is taking the address of "rd." You will get the same number as that for "d."
Obviously, one example is all it takes to disprove the assertion that a reference always takes up memory.
Ilya Lipovsky wrote: By the way, are you sure that your wonderful Microsoft compiler didn't simply optimize the reference variable away?
Well, in a sense it did, because 'ri' is just another name for the object stored at array[3]. It didn't need to actually reserve storage for the variable. And that's the point; it's what the Standard says. Perhaps it's not that Microsoft's compiler is so wonderful, but that your compiler is less-than-wonderful that you don't see the same effect.
Ilya Lipovsky wrote: I hope that Gatik will forgive me, if I interpret him that by saying that "many people think of a reference variable as an alias" he meant to say this:
Many people think that a declared&defined reference variable is interpreted by the compiler to be just another name for the original variable.
And that's as simple as that. Gatik then proceeded to say that the above notion is generally not true. What's your problem with that?
My problem with that is that that definition of reference is exactly true: a reference is just a name for an object. Please see the Standard, or Stroustrup, or any number of reputable C++ authors if you don't believe me. If that's what Gatik means by aliasing (and I'm not sure that it is), then his assertion that a reference is not an alias is incorrect.
Ilya Lipovsky wrote: Another interesting example is taking the address of "rd." You will get the same number as that for "d."
Guess what. You can't take the address of a reference. That is, the following is illegal:
double d;<br />
double& rd = d;<br />
double&* prd = &rd;
Ilya Lipovsky wrote: That's why I view reference variable as const pointers with a twist. I don't know how the Microsoft compiler implements them, but in my case: if a reference variable doesn't occupy any space, that means that, if a corresponding const pointer is defined instead, it, too, will be optimized away.
You may view them any way you want to, but to me it's confusing to introduce the concept pointers into the mix: a pointer is a name for an object. Period. In some situations, it requires no storage -- it's just a convenience to the programmer. It's nice, because you don't need to test it for null when you receive one.
I think what is going on here is that Gatik is working at too many levels at once. At the level of the programmer, a reference is certainly not a pointer, and it's not particularly helpful to think of them in any such light. At a different level, the level of the compiler implementor (and possibly the developer who is counting cycles/bytes), you need to know how they're implemented. But mixing levels inappropriately is confusing. And insisting that references always take up memory is just incorrect.
regards,
Jeff
|
|
|
|
|
Don't forget: it's not const pointers, but automatically dereferenced const pointers.
But I get your point, Jeff. On the level of C++ semantics you _may_ be right. I can't check you on that one, since I don't have the standard on hand. I still have my doubt, though, since what you quoted from there says: "A reference can be thought of as the name of an object". What is the meaning of "can?" The same as "should?"
On the level of implementation, things do get tricky. In my case Gatik is absolutely right! In your case... I didn't see you following up on my request to you to check what testfunc3 gets compiled into without optimizations being turned on.
Also, don't be too quick to criticize gcc: if I turn the -O3 optimization on, my modified testfunc1, testfunc2, and testfunc3 all produce the same very short code. (I modified them to force the optimizer to not throw them away, since they previously returned void and had no side effects).
int testfunc1() __attribute__ ((noinline));<br />
int testfunc2() __attribute__ ((noinline));<br />
int testfunc3() __attribute__ ((noinline));<br />
<br />
int testfunc1()<br />
{<br />
int array[10] = {0};
int& ri = array[3];
ri = 4;
return ri;<br />
}<br />
<br />
int testfunc2()<br />
{<br />
int array[10] = {0};
array[3] = 4;<br />
return array[3];<br />
}<br />
<br />
int testfunc3()<br />
{<br />
int array[10] = {0};
int *const rp = &array[3];
*rp = 4;
return *rp;<br />
}<br />
<br />
int main()<br />
{<br />
std::cout <<testfunc1()<< std::endl;<br />
std::cout <<testfunc2()<< std::endl;<br />
std::cout <<testfunc3()<< std::endl;<br />
}<br />
the C++ code above will produce the following assembly definitions for the testfuncs:
_Z9testfunc1v:<br />
.LFB1525:<br />
stwu 1,-16(1)<br />
.LCFI2:<br />
li 3,4<br />
addi 1,1,16<br />
blr<br />
.LFE1525:<br />
.size _Z9testfunc1v, .-_Z9testfunc1v<br />
<br />
<br />
.align 2<br />
.globl _Z9testfunc2v<br />
.type _Z9testfunc2v, @function<br />
_Z9testfunc2v:<br />
.LFB1526:<br />
stwu 1,-16(1)<br />
.LCFI3:<br />
li 3,4<br />
addi 1,1,16<br />
blr<br />
.LFE1526:<br />
.size _Z9testfunc2v, .-_Z9testfunc2v<br />
<br />
<br />
.align 2<br />
.globl _Z9testfunc3v<br />
.type _Z9testfunc3v, @function<br />
_Z9testfunc3v:<br />
.LFB1527:<br />
stwu 1,-16(1)<br />
.LCFI4:<br />
li 3,4<br />
addi 1,1,16<br />
blr<br />
.LFE1527:<br />
.size _Z9testfunc3v, .-_Z9testfunc3v<br />
I tend to work with assembly so that's why I put my 10 cents into this whole discussion.
Regards,
Ilya
|
|
|
|
|
It doesn't matter if pointers might be optimized away. The reference still doesn't take any memory, independent from what happens with pointers.
The article claims that "A Reference takes its own space in memory", wich is proofen to be wrong.
Further the article says: "The example below proofs that a C++ reference is not an Alias and takes its own space into the memory." followed by an example. But an example can never proof that something is right. Otherwise I could "proof" that all odd numbers are prime numbers. 3 is a prime numbber; QED.
|
|
|
|
|
Hi Matthias,
I'd like to ask one question to clarify your confusion.
Is it possible to write an assembly code in which you can specify one variable which will not take any space in memory/registers ? if yes, the concept mentioned above is wrong and I aplogize for that.
No body in the discussions till now being able to proof that a reference will not take its own space in the memory. some people say its wrong but I dont understand why . I can clarify if more confusion's are there.
Regards
Gatik
|
|
|
|
|
OK, back into the fray.
Gatik G wrote: Is it possible to write an assembly code in which you can specify one variable which will not take any space in memory/registers ? if yes, the concept mentioned above is wrong and I aplogize for that.
Where in your article do you talk about registers? They are not generally considered to be part of memory space (though some architectures do map registers into memory space). Here is what you say:
Gatik G wrote: A reference variable is just another pointer variable which will take its own space in memory.
This seems to imply that a reference variable has its own location in the memory space, separate from other variables. Since registers get re-used, you cannot include registers in your criterion. In general, most things go through registers at one time or another.
Gatik G wrote: No body in the discussions till now being able to proof that a reference will not take its own space in the memory.
I gave you an example in a prior post, with assembly code output to prove it. Would you like another?
void func( int* array, int val )<br />
{<br />
array[4] = val;
int& ri = array[3];
ri = val;
}<br />
Here is the generated assembly:
PUBLIC ?func@@YAXPAHH@Z ; func<br />
_TEXT SEGMENT<br />
_array$ = 8<br />
_val$ = 12<br />
?func@@YAXPAHH@Z PROC NEAR ; func<br />
; File ref2.cpp<br />
; Line 7<br />
mov ecx, DWORD PTR _array$[esp-4]<br />
mov eax, DWORD PTR _val$[esp-4]<br />
mov DWORD PTR [ecx+16], eax<br />
; Line 9<br />
mov DWORD PTR [ecx+12], eax<br />
; Line 10<br />
ret 0<br />
?func@@YAXPAHH@Z ENDP ; func<br />
_TEXT ENDS<br />
<br />
Do you need to have this explained to you, or can you figure out that nowhere does the reference 'ri' exist in a separate location in memory: the code loads the address of the array into the ecx register, and then accesses the appropriate array entry via offset from the register contents. There is no place where the variable 'ri' is stored; not in memory, not in the register.
Gatik G wrote: some people say its wrong but I dont understand why.
Just because you don't understand why it's wrong doesn't make it correct.
Again, let's go back to your article. You say in your Introduction:
Gatik G wrote: What is meant by references in C++? A reference is generally thought of an aliasing of the variable it refers to. I hate the definition of references being and Alias of a variable in C++. In this article I will try to explain that there is nothing known as aliasing in C++.
You go on and on about aliasing, but you never explain why you don't believe in it, or don't like them. When asked, you don't provide a definition. What is aliasing, in your mind? Why is it so hateful to you?
Gatik G wrote: A reference variable is just another pointer variable which will take its own space in memory.
This is contrary to what the Standard says, and contrary to examples given to you.
You might also check out the book "C++ Common Knowledge", by Stephen C. Dewhurst. Chapter 5 is called "References Are Aliases, Not Pointers".
Gatik G wrote: The most important thing about the references is that its a type of pointer which gets automatically dereferenced (by compiler..).
The closest thing I could find to this point of view is Stroustrup's "The C++ Programming Language" (2nd ed.), where he says "The obvious implementation of a reference is as a (constant) pointer that is dereferenced each time it is used". However there is no guarantee that there will actually be a place in memory space that holds that value, which is what the Standard says. Sometimes there, is, and as shown above, sometimes there isn't.
I still find your article to be confusing, and just plain incorrect with respect to what the Standard says and to what code examples show. You can't seem to be bothered to address either criticism. Why not? You don't seem to want to actually define your concept of aliasing, which is so important to you since the point of the article is to prove that references are not aliases.
I don't know what else to tell you -- you are to be commended for trying to contribute to the community, but this article remains incorrect and unhelpful,
regards,
Jeff
|
|
|
|
|
Hi Jeff,
I request you to just look at the added section of this article. Your comments were very useful and I would like to have some comments from you regarding the new section.
Regards
Gatik
|
|
|
|
|
In my opinion Jeff is right! Standard says it's just a name for an object an the compiler builders are free to implement them with their needs to the underlying architecture considering that the reference is only a name for another object. Pointing to Gatik ... in real world we would name it an 'alias' but this is, as Jett proved is not the right terminology of programming. Wether there is optimization or not!
The standard only tells you how to implement the pattern an nothing about the generated assembly.
Thats my opinion. Am I wrong?
Live is to short to be angered about lost chances!
|
|
|
|
|
I dont see the problem, a reference is just another name for a variable (aka alias),
this means that the code:
<br />
int j=5;<br />
int &rj = j;
rj = 6;
can be replaced by the compiler to:
<br />
int j=5;<br />
j=6;<br />
however, sometimes the logic needs to know which variable is referenced in *runtime* which then simple symbol-table compile time logic cant handle, and you must have a runtime solution, the most simple and logical is using a const pointer to hold the address of the aliased variable. The most obvious example is parameter passing to a function.
however (again) some wierd architectures and wierd compilers can choose a different approach, they are free to do so.
Any decent C++ book will explain this at the chapter about references and I dont see the need for the article (or how the article helps explain things).
as for the virtual table at the end of the article, it doesnt proof a thing except that the author is confused about what aliasing is, as this example makes sense for aliasing as well.
As a1 is just another name for c1 so the code changes to c1.print(). The type of a1 isnt much relevant. True it makes sense to think of it as const pointer but it doesnt *have* to be a const pointer, it could be compile time symbol table replacment.
Iftah.
-- modified at 8:25 Wednesday 19th April, 2006
|
|
|
|
|
Ken,
Jeff may be right in the sense that Mr. Stroustroup himself would agree, and even drink tea/coffee and philosophize with him about how not to hire people who disagree. The problem, however, is that whatever the standard says is not the way some very popular compilers implement the concept of references.
There is a difference between "automatically dereferenced const pointer" and "alias."
In the first case the compiler is obligated to treat all reference variable declarations as const pointer declarations, and automatically dereference all further instances thereof, before proceeding with further compilation and potential optimizations. It should generate the same code that would be generated, if the user were to replace all uses of reference variables by dereferenced const pointer equivalents (with their initializations being the exception: not dereferenced, but having "=" replaced with "= &").
In the latter case, however, the compiler has to preprocess all instances of reference variables and resolve them into the name of the variable they reference. Basically, the same as #define'ing, only performed at compile-time, instead of preprocess-time. The code generated in this case is essentially the same as running the C preprocessor appropriately.
Gatik said that the first situation holds true, not the second one.
After initially disagreeing with him (I thought it was the second case), I performed some tests with gcc on PowerPC, and had to retract.
Again, I don't know whether Visual C++ implements reference variables with automatically dereferenced const pointers or aliases, but in gcc world the first holds true.
I still look forward to compilation results on Visual C++. Jeff indeed provided some, but I want to make sure that optimizations were turned off. Why it matters? Even with Gatik being right, the compiler *may* be smart enough to "realize" during a certain stage of compilation (like the SSA stage of gcc) that all reference variable names can be optimized away and replaced by the name of the original variable.
In a sense, it's like the alias concept, only implemented in the middle of compilation, not on the front end / parsing stage of the compiler.
-Ilya
|
|
|
|
|
Ilya Lipovsky wrote: The problem, however, is that whatever the standard says is not the way some very popular compilers implement the concept of references.
Really? That's a bold claim. Which compilers? How do they differ?
There is a difference between "automatically dereferenced const pointer" and "alias."
In the first case the compiler is obligated to treat all reference variable declarations as const pointer declarations, and automatically dereference all further instances thereof, before proceeding with further compilation and potential optimizations.
Really? Where is that statement mandated? What section of the Standard?
It should generate the same code that would be generated, if the user were to replace all uses of reference variables by dereferenced const pointer equivalents (with their initializations being the exception: not dereferenced, but having "=" replaced with "= &").
And again, where is this claim from?
In the latter case, however, the compiler has to preprocess all instances of reference variables and resolve them into the name of the variable they reference. Basically, the same as #define'ing, only performed at compile-time, instead of preprocess-time. The code generated in this case is essentially the same as running the C preprocessor appropriately.
What are your sources for this information?
Gatik said that the first situation holds true, not the second one.
If Gatik indeed thinks that an alias is another name for an object (not a variable, as you seem to think), a term that he either won't or can't define for his readers, Gatik is incorrect in his claim, something that I showed with a concrete example. If by 'alias' he means something else, his obligation is to define it.
After initially disagreeing with him (I thought it was the second case), I performed some tests with gcc on PowerPC, and had to retract.
Neither you nor Gatik seem to understand the nature of proof. It's as if Gatik were claiming that all humans are left-handed. All of the humans that he knows are left-handed, and you found a human who is left-handed, there for you think that that's a proof. Even though I can point to a human who is not left-handed, you and he continue claiming that you have proved the assertion. You are both incorrect.
Ilya Lipovsky wrote: Again, I don't know whether Visual C++ implements reference variables with automatically dereferenced const pointers or aliases, but in gcc world the first holds true.
You don't seem to understand the distinction between what the Standard requires and what it allows. Nearly everyone agrees references behave in at least some respects like a const pointer, but there is no guarantee that it is identical, nor that it be implemented using pointers. I am guessing that that holds true with gcc; I've already shown that is does with VC++. All you have shown is that gcc implements them like that in some cases, but that does not in any way constitute a proof. Have you examined the specifications and source code for gcc to validate your claim? I hope that I don't have to rustle up a copy of gcc to find a counterexample in there as well.
I still look forward to compilation results on Visual C++. Jeff indeed provided some, but I want to make sure that optimizations were turned off. Why it matters? Even with Gatik being right, the compiler *may* be smart enough to "realize" during a certain stage of compilation (like the SSA stage of gcc) that all reference variable names can be optimized away and replaced by the name of the original variable.
You seem confused on the topic of optimization. Optimization is in the realm of implementation -- there's no requirement that a compiler provide certain optimizations, nor is there a requirement that a compiler not provide certain optimizations by default. The compiler is largely free to do as it sees fit, so long as the meaning of the program is preserved. It can implement variables in registers, remove unused variables, inline functions, move computations around, and so on. Whether it does things by default, or as a result of compiler settings is irrelevant -- if the meaning of the program is preserved, it's all fair game --- it's implementation-dependent. Whether I had VC++ optimisations turned on or off does not matter -- the program was compiled into correct code, without the use of any memory space for the reference.
In the end, all of this comes down to the simple statement that "a reference is another name for an object". It's a simple notion, and is supported by the Standard and other reference literature, as well as existing compilers, even gcc. There's no requirement that a reference take up memory space, as Gatik claims. This is false, as examples have shown.
regards,
Jeff
|
|
|
|
|
Before accusing me of being "confused," **please** do read the previous posts I wrote. In those posts I gave examples of gcc generating binaries wherein reference variables and original variables *do occupy* different memory locations.
Yes, I know that optimization is a realm of implementation. Moreover, this is the realm I work in and get paid for contributing to, Sir.
My participation in the discussion is not to teach you or anyone else about the Standard, my point is to provide anyone interested with my personal annotation to the Standard. I presume that the same purpose Gatik had as well but am not going to vouch for it. You are free to read and forget it.
Also, Sir, you mistake my desire to comment with a desire to argue. I do not desire to "prove" anything in general. I only wish to illustrate that compilers have a mind of their own, while still providing an end behavior consistent with the Standard.
I do not posit any things I did not personally verify by experimentation. The terms "aliases" and "automatically dereferenced const pointers" served merely as a personal explanatory glue to explain how implementations *may* proceed compiling references. The end results *do* (verified in practice!) vary in binary, but compiled program's behaviour dictated by the standard *does not.*
The further theorizing I was engaged in *I* consider to be interesting, because it explains to me why I was getting the results I was getting with gcc, and because I deal with assembly and gcc/g++ rather often. Again, you are free to read and forget it, as it is targeted for people with some practical/similar experience. It is targeted for people who want to ruminate about the state of things in real world, not just what standards say.
End of discussion.
|
|
|
|
|
Ilya Lipovsky wrote: Before accusing me of being "confused," **please** do read the previous posts I wrote. In those posts I gave examples of gcc generating binaries wherein reference variables and original variables *do occupy* different memory locations.
Please feel free to note that what I actually said was that you "seem confused", and that was with respect to the role of optimization in compilers. It's an opinion, not an accusation, and subject to change, should you want to try to change my mind. Maybe I've misinterpreted what you said, but in prior posts, you insisted that I submit unoptimized generated code here. To what end, I can't understand -- the code would only tend to validate an entirely unsurprising conclusion: that references can be implemented as pointers. This is less strong than what the original article claims (as nearly as I can make out, because the article seems confused to me also), namely that references must be implemented as pointers. Your pursuit of the less surprising and hence, less interesting result led me to believe that you were confused on the role of optimization.
As for the rest, all noble words, indeed, but rather off the main point of the article, I think. In your prior post, you made assertions that I found questionable, and so I questioned you. For example, right at the start, you said:
The problem, however, is that whatever the standard says is not the way some very popular compilers implement the concept of references.
I found this very surprising, and asked you to clarify by naming the particular compilers, and how they differ from what the standard says about references. And what is this "concept of references" you mention? Can you actually back up what you assert?
Next, you made some claims about how a compiler must operate [snipped for brevity's sake]:
...the compiler is obligated to treat all reference variable declarations as const pointer declarations...
Again, I was surprised, and asked you to support your position. If "the compiler is obligated", then it is obligated to some set of rules (the Standard?). Who or what is it obligated to?
And so forth. You may theorize, ruminate, personally annotate, or whatever it is you think you're here for, but in the end, if you make concrete claims about the behavior of compilers vs. the Standard, you ought to be prepared to back them up. This is similar to my objections to Gatik's article wherein he claims that references are not aliases, and then can't or won't define what he means by the term 'alias'. The kindest interpretation that I can come up with for that type of behavior is "confusion".
regards,
Jeff
|
|
|
|
|
I'm explaining what I mean by the word "obligated:"
"Obligated" was a part of my definition of how references *may* be implemented as automatically dereferenced const pointers.
I also use the word "obligated" as a part of another definition of mine: how references *may* be implemented as "aliases," i.e. I essentially defined what I mean by the term "alias."
These are my definitions / convenience terms. These may or may not reflect the actual way how references are implemented in practice. Nevertheless, since I've done related work and involved experiments (some of which I already provided in earlier posts), I feel that my suggestions deserve to be on this forum.
-Ilya
|
|
|
|
|
Ilya Lipovsky wrote: I'm explaining what I mean by the word "obligated:"
"Obligated" was a part of my definition of how references *may* be implemented as automatically dereferenced const pointers.
Thank you for the clarification. There's a big difference in meaning between "obligated to be" and "may be".
I also use the word "obligated" as a part of another definition of mine: how references *may* be implemented as "aliases," i.e. I essentially defined what I mean by the term "alias."
I can't see how you could implement references using aliases. Seems strange to me. Do aliases exist in machine code? Pointers (memory addresses) do. Aliases, probably not, because an alias is a name, and machine code is generally stripped of names. Aliasing is a higher level concept, more appropriate at the C++ semantic level.
This is why I think that the topic in the original article is turned upside-down. The simplest approach, for a beginning programmer, and as a base definition, is this: A reference is an alias. Or more precisely, a reference is a name or alias for another object. This removes this useless and confusing dependence on the concept of pointers which Gatik and you (I think) evidently want to force on the concept of references.
Oh, so now you want/need to know how they're implemented? Well, OK, one way is via pointers, sure, and there are some usages that virtually require that. For one, if you want to store a reference inside a class, the best solution is likely to be a pointer. Another is when you are passing a reference to a function. But there are some instances when no pointer is required; the compiler, knowing that a reference applies in a local scope to some local object may substitute the original's address as needed, and no independent storage for the reference need be allocated.
I believe that many programmers don't care, or need to know how references are implemented; a name for another object will do fine.
The above definition of reference is in line with my own check of a real life compiler's behavior, and also with my reading of the Standard and other materials, all of which I've detailed in previous postings.
These are my definitions / convenience terms. These may or may not reflect the actual way how references are implemented in practice. Nevertheless, since I've done related work and involved experiments (some of which I already provided in earlier posts), I feel that my suggestions deserve to be on this forum.
I doubt that anyone is questioning your right to post here; I certainly am not. But posting in a public forum leaves your posts open to questioning, does it not?
I am still waiting for the names of the popular compilers that implement references contrary to the standard.
Jeff
-- modified at 14:01 Tuesday 2nd May, 2006
|
|
|
|
|
Wait a sec! There is probably indeed a context miscommunication here. I assumed that you were denying the very possibility that the generated binaries contain separate memory locations for reference variables and the original variables.
In any case, I was referring to my findings on GCC (how many times do I have to repeat?) that suggest that the binaries generated from C++ code with references are exactly the same as the ones generated from C++ with always dereferenced const pointers. Remark: I did not experiment with references to functions.
Again, make an effort and check these posts to see for yourself what I was talking about. And please don't take things out of context (like with the verb "obligated").
If you are not denying the possibility that reference variables reside in their own separate memory locations, then I say this: gcc generates code consistent with the Standard.
Regarding my examples on gcc: I realize that I did not (nor could not, unless I were an active gcc contributor) provide a general proof of required rigor - merely a hypothesis supported with examples for practical guys like myself to take a note of.
I do agree with you on one thing: it's important for anyone to draw a line between specification and implementation. Believe it or not, I saw that point from the moment you entered the forum, and I fully understand and appreciate what you try to do. You need, however, to express that point in a more "gradual" manner (as ridiculous as it may sound). Otherwise, hormons start to pump and people get defensive. That is just input/output from another human, as there is plenty of other things to get heat up about in this world. Actually, what you said in this post should have been said in the very beginning!
And speaking of *implementation*, actually, I am still waiting for you to verify how VC++ compiles code with references vs. dereferenced const pointers with optimizations turned off (for my own knowledge).
-Ilya
|
|
|
|
|
Before you complain any more about me not reading your posts (I have), perhaps you should go back and reaquaint yourself with my very first post on this topic, the first on in the thread, in which I discuss the possibility and even the reasonableness of implementing references with pointers, in some situations. I do not deny this, and never have -- I can't imagine why you would think from my postings that I could think this. Unless perhaps you never read what I wrote very carefully.
Because I have had this understanding all along, I have considered a lot of your and Gatik's examples irrelevant to the issues at hand (more left-handers, to continue my analogy of a couple of posts prior). You can stop repeating yourself -- whether a particular compiler actually implements references exactly the same as constant pointer doesn't matter in the least to me, and provides little, if any, help to the overall confusion of the article. It's why I can't be bothered to compile your code snippets with VC++ -- the result would really be irrelevant to my objects to the article.
Regarding context and the verb "obligate" -- I read what you wrote in the context you provided. How was I to know that when you wrote "obligated" you meant "permitted" or "might"?
Regarding gcc: it may or may not behave in the way that you describe. It doesn't matter a whit to me, so long as it meets the Standard with respect to references. I never claimed that it didn't, or made any claims about it's implementation. If you though that I did think any such thing, then please point out what I wrote that implied that.
Ultimately, my main point is, and has been, that the article's insistence that references are not aliases is incorrect, as is its implication that references must always take up memory space. The former is contradicted by the Standard and by reliable sources; the latter also by the Standard and by my own experiments. Will Gatik ever return to explain his use of the term 'alias', and his detestation of the very idea that a reference is an alias? Who knows?
But in the above light, I cannot help but wonder why it is that you so thoroughly agree with his conclusions. For example, you wrote:
I hope that Gatik will forgive me, if I interpret him that by saying that "many people think of a reference variable as an alias" he meant to say this:
Many people think that a declared&defined reference variable is interpreted by the compiler to be just another name for the original variable.
And that's as simple as that. Gatik then proceeded to say that the above notion is generally not true. What's your problem with that?
Gatik *does not say* that references are the same as const pointers. What he says is that they are the automatically dereferenced versions thereof. That's why in your code snippet:
My problem with that is that your restatement of Gatik's position (whether or not it accurately reflects his position), or at least what the statement's referenced "many people" think is actually always true at the level of C++, as supported by the Standard. How is a reference not an alias? At implementation level, a reference couldn't be an alias, because aliases don't exist in any machine code that I'm aware of. But that says nothing of interest, much the same as if he claimed that a reference is not a dog -- dog's don't exist in any machine code that I am aware of either. Quelle suprise.
Look, here's what he actually says in his introduction:
Gatik G wrote: What is meant by references in C++? A reference is generally thought of an aliasing of the variable it refers to. I hate the definition of references being and Alias of a variable in C++. In this article I will try to explain that there is nothing known as aliasing in C++.
Is there anything there that paragraph that talks about anything at implementation level? No, it's all about the concept of references in C++.
Further, he says:
Gatik G wrote: References are nothing but constant pointer in C++. A Statement int &i = j; will be converted by compiler to int *const i = &j; i.e References are nothing but constant pointers. They need initialization because constants must be initialized and since the pointer is constant they can't point to anything else. Lets take the same example of references in C++ and this time we will use the syntax what compiler uses when it sees references.
...
The most important thing about the references is that its a type of pointer which gets automatically dereferenced (by compiler..).
So indeed he does actually say that references are nothing but const pointers (is an automatically dereferenced pointer somehow not a pointer? Are you confusing that with the result of a dereferenced pointer?). He makes assertions about the compiler that are unsupported (maybe we should change "will" to "might". Hmmm, sound familiar?) He makes claims about the syntax that the compiler uses when it sees references. Again, unsupported. More reading out of context? I don't think so. And he never, ever, allows for the possibility that a reference might not take up memory space.
I'm sorry, but his introduction is so riddled with confusion, that it's hardly useful to proceed with the remainder of his article. So why do you agree with him so happily?
And by the way, just what compilers are out of sync with the Standard with respect to references, and how do they differ? You said that they exist -- so what are they?
Jeff
|
|
|
|
|
Regarding what I said about existence of compilers that implement references not consistently with the Standard: I retracted that assertion (see the bold type in my previous post).
I did it, because I saw that you did not use what the Standard was saying as a denial of the possibility of references being resolved into ADCPs (automatically dereferenced const pointers). Since I don't have the Standard on hand, and I am not anal about it, I wanted to see whether you connect your understanding of the Standard to insisting (as formerly&mistakenly I thought that you did) that references cannot resolve into ADCPs. I took the Standard as "hostage," if you may.
Hope that makes sense .
In my previous post I completely recognized that you were not implying that references can't resolve into ADCPs, so restated myself.
I was so "happily" agreeing with Gatik, because even before you joined the discussion I made another mistake. I originally thought that references do not resolve into ADCPs, but instead are "aliases," as was defined by me.
Obviously, both you and Gatik would strongly disagree with that. I realized that I was wrong after performing my experiments with gcc and admitted it. Probably, from then on I proceeded by inertia, thus so "happily" disagreeing with you. I took his article as a comment on implementation, not as a comment of how things should be. Thus, I was wrong yet another time.
In total, I was wrong thrice:
1) I thought that references are strictly "aliases" (compile-time ones, as defined by me). Corrected myself before Gatik.
2) Thought that Gatik was enlightening the crowd about implementation. Not true, in light of the pasted text. Apparently he's talking about specification.
3) Mistook your fanaticism in defending the Constitution... sorry, the Standard, as a denial of the obvious. Corrected myself before you (right?).
Hopefully, those things answer everything completely.
-Ilya
P.S. Sorry for the joking tone, but the hour is late, and I just can't things too seriously right now.
|
|
|
|
|
Well, that's a very gracious post, Ilya. What can I do but marvel, and back off? I think that ultimately we may have been in violent agreement on some points, and I'm sorry for any misunderstanding that may have been caused by me.
No need to apologize for your joking tone -- the tone was probably getting too heavy anyways. I certainly felt it in some of my own posts. I think that we're clear now -- if only we could get Gatik to come around and clarify his article.
regards,
Jeff
|
|
|
|
|
Let me also answer:
>I can't see how you could implement references using aliases. Seems strange to me. Do aliases exist in machine code? Pointers (memory addresses) do. Aliases, probably not, because an alias is a name, and machine code is generally stripped of names. Aliasing is a higher level concept, more appropriate at the C++ semantic level.
Exactly! By "alias" I meant that the compiler may convert all uses of reference variables into the names of the variables they refer to (if such use is permitted) at parse / early compile time. That's why I said that it may be like the #define statement, only at early compile time. The produced binary will not contain any mention of the reference variable, which may explain why you did not see it in your examples.
I also said that gcc appears to be interesting in this respect: it most probably resolves references into dereferenced const pointers and then proceeds into further compilation.
If no optimizations are enabled, one can detect the presence of the reference variable. In fact, the produced code looks the same as if dereferenced const pointers were used instead.
However, if optimizations are anabled, gcc (v4.0+) performs alias analysis and attempts to get rid of references (by resolving them into the actual variables when possible). Since references were resolved into const pointers, the same thing is being done to const pointers as well.
That's why I said that it's like the "alias" concept (as was defined by me), only implemented during the optimization stage, not at the early stage of compilation.
|
|
|
|
|