|
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/
|
|
|
|
|
I think the original point is that a reference is not some kind of alias that requires no memory! The double example is better, though.
|
|
|
|
|
The C++ standard only describes the behaviour of references; it does not say how they are implemented. Commonly they are in fact implemented as const pointers behind the scenes and it may be helpful to point that out. However, that is an implementation detail, not part of the definition of a reference.
John Carson
"To argue with a man who has renounced the use and authority of reason is like administering medicine to the dead."
Thomas Paine
|
|
|
|
|