|
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.
|
|
|
|
|
I'm sorry, but adding irrelevant information to an incorrect and confusing article doesn't make it any less incorrect and confusing. Until you address some of the specific problems in your Introduction, which I have mentioned several times already, this article will remain, for me, completely useless.
Well, useless except for one thing: since I participate in technical interviews where I work, I now have a new interview question to explore: "what is the difference between a referenc and a pointer?" A candidate who claims that a reference is a constant pointer or that a reference always takes up memory space will have some serious follow-up to face.
regards,
Jeff
|
|
|
|
|
Hi jef,
Well I was out of action for a while but again I dont agree with your point. The problem is that you are mixing compiler optimization with reference implementation unnecessary. for example
when you call a function the you might get few parameters inside the registers instead of being into the stack. Then if you argue that when I haven't mentioned __fastcall why some parameters goes to registers.
furthermore a compiler can optimize only things it can foresee, and for the variable about which it cant foresee where the variables are going to be used.
I can agree with one point that I should rename this article as "Compilers handling of reference variables when it cant foresee its usage".
For my perspective if somebody in my interview says that the references are alias, they have serious consequences to face actually.
The thing is you have shown all the examples which is having compiler optimization. Well I want to come into conclusion so I just wanted one thing from you or Ilya that keeping in mind what the standard says, if you have to implement references how you would have written compiler to implement that.
I would like to make a point over here that Concept of having an Alias which will not take any space, if it would have been the case, there is no reason why "C" language skips that. everybody want to save space using aliases, isn't it ?
Any comments
Regards
Gatik
|
|
|
|
|
Well, once again, you have either forgotten to, or chose not to define "alias", which you so strongly object to. In your article, you say:
What is meant by references in C++? A reference is generally thought of an aliasing of the variable it refers to.
Yet you never define what aliasing is. Do you define it as "another name for an object", which would make it identical to what references are defined to be, in the Standard and by other knowledgeable authors? Or is it something else? You've been asked to provide your definition several times -- until you do so, it's very difficult to understand what your difficulty with the concept of references being aliases actually is.
I hate the definition of references being and Alias of a variable in C++.
Whether you hate it or not, references are aliases, if aliases are another name for an object.
In this article I will try to explain that there is nothing known as aliasing in C++.
You prove no such thing -- you merely show examples where references are implemented as pointers. I have shown you examples where references can be seen to be implemented as aliases, i.e., where a reference is used in C++ source, no separate pointer representing that reference appears in the generated machine code. This disproves your theory, and so does the fact that your theory contradicts against what the Standard says.
To continue with your latest reply:
Gatik G wrote: Well I was out of action for a while but again I dont agree with your point. The problem is that you are mixing compiler optimization with reference implementation unnecessary. for example
There is no problem here; compilers are obligated to honor the semantics of C++ constructs when compiling code. Even if optimization is on, that optimization doesn't allow the compiler to change the semantics of C++ programs. The implementation of references, regardless of optimization, in C++ does not require pointers to be used, nor does it require that space be allocated to implement a reference.
A similar example: in the expression i / 2, where i is an int, the compiler is free to do an actual division, or do a right shift (i >> 1), if it doesn't change the meaning of the program? Is it optimization? Perhaps. Is that somehow invalid? No, because the program does the same thing either way.
Gatik G wrote: For my perspective if somebody in my interview says that the references are alias, they have serious consequences to face actually.
Why, because the interviewee is actually correct, and you are not? They can easily point to the Standard and other reputable authors to support that references are exactly aliases. You cannot. It's a different question than "how might you implement references?"
Gatik G wrote: The thing is you have shown all the examples which is having compiler optimization. Well I want to come into conclusion so I just wanted one thing from you or Ilya that keeping in mind what the standard says, if you have to implement references how you would have written compiler to implement that.
Again, you somehow seem to think that compiler optimization is somehow invalid or unfair. It is not; it is the business of the compiler. The compiler is perfectly allowed to optimize references away in the generated code if it doesn't change the meaning of the program. In some cases, it is very difficult to do so, but in others it is perfectly possible, and desired behavior.
Gatik G wrote: I would like to make a point over here that Concept of having an Alias which will not take any space, if it would have been the case, there is no reason why "C" language skips that. everybody want to save space using aliases, isn't it ?
What does the "C" language have to do with this? We are discussing C++, are we not? Have you even bothered to read the Standard? Do you have any other articles that back up what you are trying to say? Will you at least attempt to define "aliasing" for us, because your article is hopelessly confused without that definition (though it's possibly hopelessly incorrect if you do define it as most developers probably would).
regards,
Jeff
|
|
|
|
|
jefito wrote: On aliasing, the Standard only uses the term mainly (and normatively) to refer to namespace aliasing, and only in passing with respect to references, mainly in footnotes. The latter seems to be closer to what you are referring to, but it is nowhere defined in the Standard.
On references, the Standard says:
1) 'a reference can be thought of as a name of an object'
I am in agreement with you Jeff.
In fact, I just checked out what Marshall Cline says about references in the C++ FAQ Lite at http://www.parashift.com/c++-faq-lite/references.html . There he states
quote :
[8.1] What is a reference?
An alias (an alternate name) for an object.
References are frequently used for pass-by-reference:
<sample cut>
End Quote
AAR
|
|
|
|
|
It looks like both points of view have their good arguments.
The easiest way to find the truth is, of course, to examine the compiler's code. But even in this case, I believe, behavior mostly depends on optimization options.
However, both (clever and experienced, provided by author and commetators) arguments result to this conclusion:
when there is no need in storing any data (i.e., use memory) for the reference - it is just an alias for another variable. The compiler uses it as an abstract compile-time essence. Working with it, it can optimize its usage, just replace it with referenced variable address, or use it as-is (then it becomes a real essence).
In case, when memory is needed (e.g., forced by a programmer, using in a Class, etc..) in most cases "* const" is used.
So, the source of the arguing here is based just on some wrong statements:
"reference is not an alias" - WRONG, CORRECT: "reference can be just an alias (when it is enough)"
"reference is a constant pointer" - WRONG, CORRECT: "reference functionality can be implemented using "const pointer" when it requires memory space"
So, a smart coder should NOT rely on any of that two stated facts, and make conclusions based on his current code and compiler realization.
modified 8-Apr-21 14:38pm.
|
|
|
|
|
To the author: the article is a good intro, but the proof that references occupy their own memory in the machine, i.e. not aliases, is insufficient, and in fact is wrong in certain cases (at least in case of gcc):
For example:
int main()
{
int val = 3;
int &ref = val;
int *const ptr = &val;
fprintf(stdout, "This is the address of val: %d\n", &val); //#1
fprintf(stdout, "This is the address of ref: %d\n", &ref); //#2
fprintf(stdout, "This is the address of ptr: %d\n", &ptr); //#3
class Test
{
double &i; // double *const i;
double &j; // double *const j;
double &k; // double *const k;
};
fprintf(stdout, "This is the size of Test: %d\n", sizeof(Test));
return EXIT_SUCCESS;
}
fprintf statements #1 and #2 will print the same value. #3 will print a different value (with gcc).
This proves that references are aliases, syntactic objects to be resolved at compile-time. Pointers, on the other hand, are physical variables and either may or may not be optimized away during compilation.
The fact that the "Test" class has size 12, doesn't mean that reference types have sizes. It merely indicates that in that particular situation the compiler could not resolve the aliases at compile time, so it assumed that the references will be initialized at construction time (run time). Thus, it *had to turn* those aliases into constant pointers.
Check it with VC++ compiler to confirm/reject my take on the issue.
By the way, notice that the members of "Test" are references to double precision floating point type variables. I did it so that it's clear that the compiler doesn't resolve references into actual POD types, but instead resolves them into pointers - exactly what you try to convey in your article.
-Ilya
|
|
|
|
|
ilya l wrote: fprintf statements #1 and #2 will print the same value. #3 will print a different value (with gcc).
That's because you have &ptr and not &*ptr or ptr in statement #3.
ilya l wrote: The fact that the "Test" class has size 12, doesn't mean that reference types have sizes. It merely indicates that in that particular situation the compiler could not resolve the aliases at compile time, so it assumed that the references will be initialized at construction time (run time). Thus, it *had to turn* those aliases into constant pointers.
Using this code:
#include <iostream><br />
<br />
struct Test<br />
{<br />
double & x_;<br />
double & y_;<br />
Test (double & x, double & y) : x_(x), y_(y) {}<br />
};<br />
<br />
int main ()<br />
{<br />
double a = 0, b = 1;<br />
Test test (a, b);<br />
std::cout << "size of Test is " << sizeof(Test) << std::endl;<br />
std::cout << "size of test is " << sizeof(test) << std::endl;<br />
return 0;<br />
}
MSVC2005 printed 8 in both cases. Are you saying that gcc would print 16 on the second line?
Sure, compilers generate the same code for references and const pointers. But why would i care about that? All i need to know is that in the context of my source code, reference is an alias of some object and that it can't be NULL (so there is no need for asserts to check that).
|
|
|
|
|
About &*ptr: *ptr resolves to val. &val is the address of the actual object. So what?? My goal was to point out that "ptr" is a physical variable, and "ref" is somewhat more exotic, not possessing an actual memory location whether you apply compiler optimizations or not.
Regarding the "Test" class. No, Paulius: I am *not* saying that sizes of Test or test are supposed to be 16 (in gcc). I gave that example with the "Test" class merely to *support* the author's general point regarding references not being actual types. I just deemed his example with ints (whose sizes are the same as "int *") didn't illustrate his point strong enough.
So why would you care if the compiler generates same code for references and const pointers? You may happen to need to access the physical address of a reference variable (say, through an external routine), but if the address resolves to the address of the referenced variable, you do need to know about this fact so as not to modify the value of the referenced variable accidentally.
|
|
|
|
|
The original statement: "...is wrong in certain cases..." is a bit misleading. My statement refers to the author's position that references resolve into constant pointers, not the proof itself.
|
|
|
|
|
Hi ilya I. I am sorry but you are totally mistaken, and you have written wrong code to check the values. in you code snippet
int main()
{
int val = 3;
int &ref = val;
int *const ptr = &val;
fprintf(stdout, "This is the address of val: %d\n", &val); //#1
fprintf(stdout, "This is the address of ref: %d\n", &ref); //#2
fprintf(stdout, "This is the address of ptr: %d\n", &ptr); //#3
return EXIT_SUCCESS;
}
#3 is wrong. you forget the fact that reference variables are automatically dereferenced. so you need to write fprintf statement as......
fprintf(stdout, "This is the address of ptr: %d\n", &*ptr); //#3
Now if you will check the output it will be same.
FurtherMore.... suppose you are a compiler, there is no way you can maintain Aliases in binary executable. Still if you dont belive try to see the assembly generated for all the 3 statements.
Hope This clarifies the things........
Regards
Gatik
-- modified at 23:21 Tuesday 14th March, 2006
|
|
|
|
|
Hi Gatik,
Yes true, aliases in the binary executable are not preserved, indeed. That's the whole point of aliases. (Btw, if you make val and ref global, then the <ref> label will simply contain the address of the <val> label in the assembly output).
Again, the whole point of my original argument is this: Reference variables don't occupy separate memory cells unless they absolutely must to (e.g in "class Test" case or in case you globalize them). This is, what I said, distinguishes them from pointers, entities with their own separate memory cells (unless they get optimized away).
My regards to you,
Ilya
|
|
|
|
|
Eh, bad formatting! Change:
(Btw, if you make val and ref global, then the label will simply contain the address of the label in the assembly output).
Into:
(Btw, if you make val and ref global, then the ref label will simply contain the address of the val label in the assembly output).
|
|
|
|
|
The article's fine as far as it goes, but it doesn't go nearly far enough. Sure, references are typically implemented as constant pointers, and usually do take space in memory - though there's no requirement that either of those points is true.
The purpose of language constructs is to let you get away from such implementation details - they are there to help think about the problem you're solving. It may help understanding to look at implementation, or it may distract you from the real point. Here I think it's distracted you.
There are two key differences between references and pointers that you must consider when deciding which to use: pointers can be NULL and they can point to different target objects over their lifetime.
So the earlier comment about their suitability for parameter passing is spot on. A good use for a reference is in the case where you're passing a big object "by reference" (thus the name!) and you guarantee that it's always going to be a valid object.
Another good place to use references is in a class, where you're going to want a permanent connection to another object, and again can guarantee that the lifetime of the target object is at least as great as your container.
class Container
{
Target &tgt;
Container(Target &t) : tgt(t){}
};
|
|
|
|
|
C++ Reference is often used for polymorphism, such as:
class Base
{
public:
virtual void Foo() = 0;
};
class Derived : public Base
{
public:
virtual void Foo()
{
// Do some thing....
}
};
class Derived2 : public Base
{
public:
virtual void Foo()
{
// Do another thing....
}
};
void Foo(Base& obj)
{
obj.Foo();
}
int main()
{
Derived obj1;
Derived obj2;
Foo(obj1);
Foo(obj2);
return 0;
}
|
|
|
|
|
You don't say/show anything about paramter passing, an area where references have most sense.
- Goran.
|
|
|
|
|
because its equivalent to the statement int &j = i;
-- modified at 5:29 Friday 10th March, 2006
|
|
|
|
|
No it's not.
It is a concept which is known only by those who already use references, not by beginners. Who should be your audience?
- Goran.
|
|
|
|
|
Agreed Will change the level to intermediate.
|
|
|
|
|
Regarding the code snippet in last section "A Reference takes its own space in memory", it does not prove that reference takes its own space in memory as integer is usually the same size as pointer on a 32 bit system.
|
|
|
|
|
If im not mistaken, he's just used a (very confusingly) bad example.
no offense to the author, an otherwise good article .
<br />
struct Test<br />
{ <br />
double& a;<br />
double& b;<br />
double& c;<br />
};<br />
<br />
int main()<br />
{<br />
std::cout << "size: double = "<br />
<< sizeof( double )<br />
<< std::endl;<br />
<br />
std::cout << "size: struct Test = "<br />
<< sizeof( Test )<br />
<< std::endl;<br />
<br />
return 0;<br />
}<br />
the Test structure contains constant pointers (the references) which is why it returns sizeof as 12 bytes (three 32bit pointers), we know that a double is 8bytes and that 3 x 8 = 24.
http://www.silvermace.com/
|
|
|
|
|