[SOLVED] When Ampersand(&) is needed?
-
hello,
I just saw some code and i can't understand the usage of the ampersand.
the code that i saw is similar to this,
@void something(const QString &string);
//no compile error
@the codes that i wrote for expirement
@void something(const QString string);
//no compile error
@@void something(QString &string);
//compile error
@@void something(QString string);
//no compile error
@and also i saw something like this
@QStringList list = populateStringList();
foreach(QString &item,list){
if(item=="hello"){
......}
}
//no compile error@the code that i wrote,
@QStringList list = populateStringList();
foreach(QString item,list){
if(item=="hello"){
......}
}
//no compile error@I understand that the something() method that it is a const one,but i can't understand the "&" usage.Also i can't understand the difference between the two foreach cases.
In addition no matter which foreach code sample i use my application works correctly. -
First of all, you need to understand that C++ defines the concept of reference. A simple (lvalue) reference, is identified by an « & ». A reference is just a name for a thing. In other words, a reference defines a synonym for something :
@
int a = 10;
int &ra = a;
@Here, ra is a reference. Manipulating ra is the same as manipulating a. Those are two names for the same thing (a literal integer).
With that in mind, let's now examine those two expressions :
@
void something(const QString &string);
@@
void something(QString string);
@With the second one, each time you send a QString to something, the QString is copied. Thus, this is in fact a copy of the QString that you manipulate inside the function. However, Qt implements what they call « Implicit Sharing » (an other name for « Copy On Write » pattern). Thus, the QString is not entirely copied. Instead datas are just shared among QString instances, until one tries to modify the QString, then a deep copy is made.
However, with the first one, no copy at all is needed. Instead, inside your something function, you are manipulating the same QString object. The reference being qualified as « const », you're not able to modify this object, because it is in « read only ».
To sum up briefly, the second expression needs to perform a copy, where as the first doesn't (then the first is better, even with implicit sharing, which is not free).
@
void something(QString &string);
@Here the QString object is also a reference. However, this is not const. If you try to do something like this :
@something("Hello");@ it won't compile because the literal string "Hello" (which is of type const char[ 6 ]) will result in a temporary (rvalue) QString. The C++ standard forbids rvalues to bind on non-const lvalues reference (the new C++11 standard defines a new concept of rvalue reference, but you don't need to care). If you want it to compile, you have to write something like :
@
QString myStr("foo");
something(myStr);
@But then you can expect something to have some side effects, like modifying your QString object.
@void something(const QString string);@
const here is not really useful, since the string object is a copy. If just may be useful if you want the compiler to raise an error if you try modifying the string object.
So, in C++, to avoid useless copies when passing parameters into function, we use references (identified by an « & »). Generally, those references are const-qualified, to tell the compiler « Hey, I won't modify this object ». Furthermore, const-reference are able to be bound to temporary objects (like I said before).
-
In addition, you should keep in mind that C++ uses the & as reference operator to retrieve the address of an object in memory as well.
@
QObject object;
QObject* objectPointer = &object;
@So the meaning of & is a bit different dependig whether used with types or variables.
-
[quote author="octal" date="1313849117"]
lvalue
[/quote]can you explain to me this term?
[quote]
the literal string "Hello" (which is of type const char[ 6 ]) will result in a temporary (rvalue)
[/quote]Are you sure that hello is a const char[6]???
@const char[] hello = "hello";
qDebug() << hello[6];@This doesn't give an ouput.I am almost sure that in c++ arrays count from zero so 5 is 4.
[quote author="Lukas Geyer" date="1313852985"]
So the meaning of & is a bit different dependig whether used with types or variables.[/quote]@//it is used in variables
QObject obj;
QWidget wid = &obj;//it is used in types
something(const QString &string);@
correct?
Moreover,
@void startJob(Job &work){
.....
delete &work;}void doJob(){
Job *doing = new Job;
startJob(doing);}
//no compiler error
@In this situation why the pointer is valid?
Is this because of the usage of the ampersand?@void startJob(Job &work)@
In conclusion,after a little search,i found a good article and i understand the reference mechanism.
So the reference is being used in order to avoid copying(making slower) our application.
Is there any reason,for which i should use the reference mech in my functions?
thank you for your help :)
-
bq. can you explain to me this term?
an lvalue refers to an expression that has a name and persists in memory, as opposite to rvalue which refers to a temporary.
bq.
Are you sure that hello is a const char6???
1
2
const char[] hello = "hello";
qDebug() << hello[6];
This doesn’t give an ouput.I am almost sure that in c++ arrays count from zero so 5 is 4.Yes in fact, this is « const char[ 5 ] ». But I meant the type of "hello" is « const char[ 5 ] », my bad.
EDIT: erf, I was right, you have a final '\0', so this is const char[ 6 ].
@
//it is used in variables
QObject obj;
QWidget wid = &obj;
@I don't understand what you're trying to achieve here.
bq. Is there any reason,for which i should use the reference mech in my functions?
anytime you don't need useless copies.
Anyway, I think you need to take a C++ course before going on with Qt. You can look at the wiki for some good books :)
-
[quote author="octal" date="1313867563"]bq. can you explain to me this term?
Yes in fact, this is « const char[ 5 ] ». But I meant the type of "hello" is « const char[ 5 ] »
[/quote]I can produce an output with const char [5] only with 4 or less.
[quote]
@
//it is used in variables
QObject obj;
QWidget wid = &obj;
@I don't understand what you're trying to achieve here.
[/quote]I am trying to tell you if understand correctly when the reference is used for memory and when it doesn't.
-
@void something(QString &string);@ This is call by reference. Like its said before, use of & is different[Than the usuall meaning "address of", am sure that makes all the confusions ;)]. Its just telling compiler, okay dont copy, just save time and memory.
Now, If you want to save the copying time, memory, and also don't want to change the original value, just put 'const'
@void something(const QString &string);@And when you 'call by value' , @void something(QString string);
void something(const QString string);@ ,Still, Qt is smarter ;), cow [copy on write] comes to action,like its said before.The errors you got , probably because of something in the declaration part, i suppose.
..............................................................................Interestingly, foreach keyword has something to tell. :) It is a macro and is implemented using the preprocessor. You should go through the "docs":http://doc.qt.nokia.com/latest/containers.html#the-foreach-keyword.
And i think,here again same laws as above.. [ copy / dont copy ]
@QStringList list = populateStringList();
foreach(QString &item,list){ //dont copy, direct access
if(item=="hello"){
......}
//EDIT:
foreach(const QString &item,list){ //dont copy, no change allowed!
if(item=="hello"){
......}
//EDIT : 2
foreach(QString item,list){ // copy!
if(item=="hello"){
......}
@EDIT 2:
NOTE : Its clear in the document
Qt automatically takes a copy of the container when it enters a foreach loop. If you modify the container as you are iterating, that won't affect the loop. (If you do not modify the container, the copy still takes place, but thanks to implicit sharing copying a container is very fast.)Since foreach creates a copy of the container, using a non-const reference for the variable does not allow you to modify the original container. It only affects the copy, which is probably not what you want.
-
[quote author="Giorgos Tsiapaliwkas" date="1313865773"]
[quote]
the literal string "Hello" (which is of type const char[ 6 ]) will result in a temporary (rvalue)
[/quote]Are you sure that hello is a const char[6]???
@const char[] hello = "hello";
qDebug() << hello[6];@This doesn't give an ouput.I am almost sure that in c++ arrays count from zero so 5 is 4.
[/quote]There is a difference between char[] as a type and char[] as an index access.
- const char[] hello = "hello" reserves a consecutive block of memory which stores the characters of the word "hello" at position 0 - 4 and a trailing '\0' at position 5 which terminates strings in C++.
- hello[ 6 ] returns the character stored at position 6 in this consecutive block of memory. Obviously there is none, because the positions range from 0 to 5. Thus you get no output.
[quote author="Giorgos Tsiapaliwkas" date="1313865773"][quote author="Lukas Geyer" date="1313852985"]
So the meaning of & is a bit different dependig whether used with types or variables.[/quote]@//it is used in variables
QObject obj;
QWidget wid = &obj;//it is used in types
something(const QString &string);@
correct?[/quote]
The idea is right, the code is wrong. The reference operator returns the address of an object, not an object. This address has to be stored in a variable of type "pointer to object", not "object". Take another look at the code I've posted.
In addition, the pointer has to be of the same type as the object. Otherwise you will have to do an explicit type conversion using a cast (or this is done for you implicitly, as for example in inheritance hierarchies).
[quote author="Giorgos Tsiapaliwkas" date="1313865773"]
Moreover,
@void startJob(Job &work){
.....
delete &work;}void doJob(){
Job *doing = new Job;
startJob(doing);}
//no compiler error
@In this situation why the pointer is valid?
Is this because of the usage of the ampersand?[/quote]I don't think this code compiles.
startJob(Job& work) expects an parameter of type Job, whereas the parameter you pass doing is of type pointer to Job (Job*). That's two different things, two different types.
-
[quote author="Lukas Geyer" date="1313852985"]
I don't think this code compiles.
[/quote]Yes you have right.The code that compiles is this one,
@void startJob(Job &work){
.....
delete &work;}void doJob(){
Job *doing = new Job;
startJob(*doing);}@thanks you all of you for help and for your time.
I will mark the thread as solved.
thanks
-
Sorry for that comment, Giorgos, but reading this code make me nervous:
@
void startJob(Job &work)
{
.....
delete &work;
}
@A reference means you get a reference to an object, but that could be loacted on the stack, the heap or even anywhere else (a const ref also in code segment). If you want to delete some memory by it, I would prefer using pointers as parameters´.
I would prefer here:
@
void startJob(Job* work)
{
.....
delete work;
}
@ -
[quote author="Gerolf" date="1314004264"]Sorry for that comment, Giorgos, but reading this code make me nervous:[/quote]
no problem.Comments are more than welcome :)
@
void startJob(Job &work)
{
.....
delete &work;
}
@this code is not writen by me.Its just a code that i came across.
[quote]I would prefer here:
@
void startJob(Job* work)
{
.....
delete work;
}
@[/quote]So do I.:)
thank you for your comment
-
Welcome.
The point why I wrote that comment is, that a pointer can be invalid (which is typically 0), a reference should never be invalid. It should always reference a valid object.