3

Consider the following:

#include <iostream>

using namespace std;

class MyClass {
    public:
        MyClass(string myMemberInitValue);
        const string getMyMember1();
    private:
        string myMember;
};

MyClass::MyClass(string myMemberInitValue) :
    myMember(myMemberInitValue)
{}

const string MyClass::getMyMember1()
{
    return myMember;
}

int main()
{
    MyClass myObj("Hello World");

    const string myVal1 = myObj.getMyMember1(); // Ok
    const string &myRef1 = myObj.getMyMember1(); // A reference to an rvalue

    ...

    return 0;
};

Normally if you use a constant reference to a r-value the lifetime of the r-value is extended to match the lifetime of the reference...

1. But what if the r-value is a member variable of an object?

Either the value gets copied or a reference to the member variable is made but that would just be valid as long as the value of the member variable doesn't change...

2. So in my understanding the value must be copied anyway, right?

3. So is there a difference between const string myVal1 = myObj.getMyMember1() and const string &myRef1 = myObj.getMyMember1() (compiler behavior, performance)?

goulashsoup
  • 2,639
  • 2
  • 34
  • 60
  • 7
    Your function returns by value, which means it returns a copy of the thing that you put in the return expression (usually). Theoretically there is no difference in behaviour or performance between the two codes you mention in #3, other than the result of `decltype(myRef1)` – M.M Apr 04 '18 at 21:22
  • Possible duplicate of [What are the differences between a pointer variable and a reference variable in C++?](https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – NonCreature0714 Apr 04 '18 at 21:57
  • 2
    @NonCreature0714 that thread doesn't seem to cover this question (which doesn't mention pointers at all) – M.M Apr 04 '18 at 22:58
  • @NonCreature0714 I took a look to the question which should answer mine because it is a DUPLICATE and couldn't see anything about const references in relation to member variables... Can you explain why you think my question is a duplication so that I'm able to make the difference more clear? – goulashsoup Apr 04 '18 at 23:43
  • I *think* it *may* be a dup because: 1) adding `const` doesn't change the behavior during assignment but after assignment, 2) There is no different behaviour if the value is copy assigned from an object or a hard-coded value, 3) Even copied `const` values, behavior is not different than any copied value and it part of its new scope. 4) `const` behavior is [well-established](https://stackoverflow.com/questions/4486326/does-const-just-mean-read-only-or-something-more) and adds nothing unique to the assignment of variables or reference variables, whether copied from a member variable or not. – NonCreature0714 Apr 05 '18 at 00:13
  • 1
    @goulashsoup That said, I defer to M.M's greater expertise, and apologize for mistakenly raising an incorrect flag. – NonCreature0714 Apr 05 '18 at 00:15
  • @M.M That is true for C++11 (which effectively mandates copy elision); but not necessarily, in theory, for C++03 (which permits but does not require it). Although probably true in practice regardless. – Nemo Apr 05 '18 at 00:18
  • @Nemo C++11 doesn't effectively mandate copy elision; my comment applies to the current version (C++17) which does – M.M Apr 05 '18 at 00:25

2 Answers2

3

There is a negligible technical difference. (As M.M pointed out in the comments.)

Firstly, this:

const string myVal1 = myObj.getMyMember1();

Initializes a string const which is a copy of the value of the member of myObj.

But this:

const string &myRef1 = myObj.getMyMember1();

Initializes a string const reference to a temporary returned by the member of myObj, and can never be reassigned.

In both cases, a copy is made... And adding const promises the compiler those values won't be reassigned.

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • I didn't downvote but _the value of `myRef1` will change if the value of the member changes_ is wrong simply because `getMyMember1()` DOES NOT return a reference. – goulashsoup Apr 04 '18 at 21:56
  • 1
    `myRef1` is not a reference to the member, but to the temporary returned from the (member) function. – Daniel Jour Apr 04 '18 at 22:07
  • @DanielJour correction made, with a link to an explanation of temporaries. – NonCreature0714 Apr 04 '18 at 22:15
  • 2
    Yes there is a technical difference, but I'm not aware of any practical difference in behavior, except if you use them with `decltype` (as M.M already commented on the question). – aschepler Apr 04 '18 at 22:34
1

Normally if you use a constant reference to a r-value the lifetime of the r-value is extended to match the lifetime of the reference.

This is incorrect. The correct statement is "If you create a const rvalue reference to and unnamed temporary object, the lifetime of that temporary object is extended to match the lifetime of the rvalue reference".

No temporary object means no lifetime extension. In particular, when a method returns a reference, it returns a reference. There's no unnamed temporary object created, so there's nothing to have its lifetime extended. Only when it returns a non-reference actual object by value AND that object is not named, so there's an actual unnamed temporary return value object that is not elided by RVO, is there an opportunity for the lifetime of that temporary to be extended.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • This code though does have a tepmorary, the method does not return a reference... – Mooing Duck Apr 05 '18 at 00:23
  • The OP talks about references to members, even though their code doesn't reflect that. So its not really clear what they're asking for, or where their confusion is, other than a basic confusion of references and values. – Chris Dodd Apr 05 '18 at 00:28