10

I am studying reference of c++, and now I am quite confused by the difference between variable name and reference. The test code is below:

class TestClass{
private:
    int num;
public:
    TestClass(int n):num(n){
        cout<<this<<" : init of : " <<this->num<<endl;
    }

    TestClass(const TestClass& t):num(t.num){
        cout<<this<<" : copyInit of : " <<this->num<<endl;
    }

};

int main(int argc, const char * argv[]){

    TestClass t = *(new TestClass(55)); //just to test copy initialization

    const TestClass t2 = TestClass(100); //option1
    const TestClass &t2 = TestClass(100); //option2


}

So now I have two options in making object, which are exclusive with each other.

In my understanding, if I use options2, the compiler makes a temporary object in the stack memory and returns the reference value to t2.

If this is right, how can I verbalize or explain the option1? It seems that the same object is created in the stack memory and computer gives a name 't2' to that object, but I do not clearly understand how this option1 is different with the option2 because a name of variables and reference are somewhat confusing.

In addition, switching options alternatively, I could see that the objects are created in different memory locations in each case. (e.g. the object of option1 was created in 0x7fff5fbff828, and that or option2 was in 0x7fff5fbff820)

Could you please explain

1. what's the difference between a variable name(option1) and reference(option2).

2. how things work differently in option 1 and 2.

3. why objects are created in different memory location in either cases.

In advance, thanks for your help!

noclew
  • 542
  • 2
  • 5
  • 13
  • I would attempt an answer at this question but your 3rd question confuses me... does the code compile? – Lews Therin Nov 03 '12 at 23:28
  • @LewsTherin If you rename the first option, it compiles. – Olaf Dietsche Nov 03 '12 at 23:29
  • Note that in `TestClass t = *(new TestClass(55));` you no longer can `delete` the allocated memory. – Jesse Good Nov 03 '12 at 23:30
  • @ Lews Therin Oh, I did not build the code having both line. I tested each option separately, commenting out the other one. But the thing is everytime I tested option1, the object is created in the memory spot A, and was created in memory spot B with the option2. – noclew Nov 03 '12 at 23:32
  • @Jesse Good Thanks! I was testing how copy initialization works with this line. – noclew Nov 03 '12 at 23:34

2 Answers2

4
const TestClass t2 = TestClass(100); //option1
const TestClass &t2 = TestClass(100); //option2

Option1:

calls the copy constructor of TestClass and passes in the temporary created on the right hand side of the "=". Copy elision eliminates unnecessary copying of objects (See Piotrs coment below).

Option 2:

You create 1 object, the temporary, which becomes bound to the reference.

  1. what's the difference between a variable name(option1) and reference(option2).

edit: I didn't know this before, but in actual fact there is not a second allocation in option 1 (Thanks Piotr) this is due to copy elision which refers to a compiler optimization technique that eliminates unnecessary copying of objects.

To use your words, the "variable name" is a block of memory that contains data. The reference is like a pointer in the sense that it points to another "variable name", but it must be initialised, and is never null.

  1. how things work differently in option 1 and 2.

As Others have said option 1 is a static type, where as option 2 could point to an instance of a derived (from TestClass) object.

  1. why objects are created in different memory location in either cases.

Despite being "identical" TestObjects(100) they are individual instances and therefore in different memory (addresses)

Caribou
  • 2,070
  • 13
  • 29
  • Can you demonstrate how the object in option 1 can be changed? It looks `const` to me. – Beta Nov 03 '12 at 23:36
  • Any proof that extra allocation occured in option1? See my example at ideone: http://ideone.com/VJiVLf. No extra allocation... – PiotrNycz Nov 03 '12 at 23:45
  • @PiotrNycz Interesting thats not what I expected as I wrote. Is it optimised out becuase of the const object? – Caribou Nov 03 '12 at 23:50
  • @Caribou Thanks a lot Caribou. It helped a lot! Then in practice, the only difference btw/ variable name and reference is about what they can hold? – noclew Nov 04 '12 at 01:17
  • 1
    It's funny I would have just jumped in an answered yes before this question, but now I find myself questioning everything I thought was true. To use your words, the "variable name" is a block of memory that contains data. The reference is like a pointer in the sense that it points to another "variable name", but it must be initialised, and is never null – Caribou Nov 04 '12 at 01:28
  • @PiotrNycz Interesting. In my understanding, variable name is not a block of memory but some abstract symbol that represents actual data on memory and is substituted by that real data when the code is compiled. Since I do not know how compilation works, I am also wondering what is the true nature of variable names.... – noclew Nov 04 '12 at 02:01
  • @PiotrNycz I was totally wrong. this article recommended by PiotrNycz really helped to understand this problem. [link] http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c – noclew Nov 04 '12 at 02:39
  • @noclew yes - nice article - as always I'm learning as well :) – Caribou Nov 04 '12 at 11:34
1

1)what's the difference between a variable name(option1) and reference(option2).

Name has static type. Reference can be bind to derived classes - we do not know the exact type of referred objects.

In your very example - for option 2 - you extended the lifetime of temporary object by creating const reference to it - see http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Normally, a temporary object lasts only until the end of the full expression in which it appears. However, C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error.


2)how things work differently in option 1 and 2.

If you call virtual function - then for variable name you know which function will be called, for references - you cannot know in more complicated example than yours.


3)why objects are created in different memory location in either cases.

They are different objects, they life in the same time - so why their memory location should be identical?

Other difference is that for option 1 you created automatic variable, for option 2 it is temporary variable - both might use different memory (stack vs. registers or some reserved memory just for temporaries)


Consider more complicated example:

class TestClass{
protected:
    int num;
public:
    TestClass(int n):num(n){
        cout<<this<<" : init of : " <<this->num<<endl;
    }
    TestClass(const TestClass& t):num(t.num){
        cout<<this<<" : copyInit of : " <<this->num<<endl;
    }
    virtual void printNum () const { cout << "NUM: " << num << endl; }
};

class TestClassDerived : public TestClass {
public:
    TestClassDerived(int n):TestClass(n){}
    virtual void printNum () const { cout << "DERIVED NUM: " << num << endl; }
};


int main(int argc, const char * argv[]){
    const TestClass t1 = TestClass(100); //option1
    const TestClass &t2 = TestClassDerived(100); //option2
    t1.printNum();
    t2.printNum();
}
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • What do you mean, "you cannot know"? It seems clear which function will be called. – Beta Nov 04 '12 at 00:24
  • 1
    Thanks for the explanation. Can I ask you for a bit more details? a1) In answer 1, could you explain more about the static type? When I changed your example code like this 'const TestClass t2 = TestClassDerived(100);', I could see that copy initialization happened and a new object of the super class type is assigned to t2. Then, does 'variable name as static type' imply that it will always represent the object with its own type, by making a copy of assigned derived object as its declared type? **--to be continued** – noclew Nov 04 '12 at 00:46
  • a2) In answer 2, When you say you cannot know, does it mean that I cannot anticipate which virtual function will be called, only by seeing the reference type and without seeing the real type of the object, just like in the case of a pointer that refers to derived classes? **--to be continued--** – noclew Nov 04 '12 at 00:50
  • 3
    @noclew - for 1: Your assignment from derived object is called slicing. t2 is of type declared on the left - it only copies the base part from `TestClassDerived(100)` - in general you should avoid it: more details: http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – PiotrNycz Nov 04 '12 at 00:59
  • 1
    @noclew - for 2: YES, you understand it exactly. Consider this: `void foo(TestClass& t); TestClassDerived d(100); foo(d);` - when you write implementation of `foo` - you do not know the most derived type of its argument. – PiotrNycz Nov 04 '12 at 01:02
  • @Beta - in this example yes it is clear. But consider const reference passed to some function - function implementation does not know the exact type. – PiotrNycz Nov 04 '12 at 01:03
  • a3) Let say I delete the options 2 line. When I clean and rebuild the code many times, the resulting object 't2' is created in the same memory location, even the resulting objects are different in each run. However, once I change t2 to &t2, the object is created in the other location. if I change &t2 back to t2 once again, the location of object is changed back to the very first location. If the change --adding and deleting '&'-- is only about the way of representing an object, why does it affect creating objects and change the memory location of the object? – noclew Nov 04 '12 at 01:08
  • 1
    @noclew good point. `&` is not only the way of representing the object. `TestClass(100)` is created in so called temporary memory. It could some RAM or registers - anything - compiler decides where it is. When inside function `TestClass t(100);` creates automatic variable - it is on the stack in every compiler I know. So there are two distinct memories - so the difference. This code: `const TestClass& t = TestClass(100);` - just extends the lifetime of temporary `TestClass(100)` to the lifetime of the const reference. – PiotrNycz Nov 04 '12 at 01:19
  • @noclew for more details see: http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ – PiotrNycz Nov 04 '12 at 01:24
  • @PiotrNycz Wow, now I can see why the locations are different. Those two declarations actually bring about different operations! And just to make sure, is there anything to remember regarding reference and variable name, other than the capacity of holding derived objects? – noclew Nov 04 '12 at 01:31
  • 1
    @noclew - maybe that non const references does not extend lifetime of an temporary object. There are probably many things to remember - I am thinking about references as something between pointers and "variable names"... You might find this helpful: http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c – PiotrNycz Nov 04 '12 at 02:05
  • @PiotrNycz Thank so much for your help. Your comments and explanations really helped this noob to understand the basics of c++! I will look into the materials that you recommended! – noclew Nov 04 '12 at 02:37