Sal
Sal

Reputation: 71

Reference variable in C++

Assume I have the following code snippet for GPoint, which has a copy constructor, assignment operator, and destructor. The same for GCircle and this has a function named GetCentre() which returns a copy of the Gpoint object(Centre).

In main or ButtonClick(), as below is it safe/valid to call GPoint &Centre = circle.GetCentre()? By doing this (if valid) we would save the time of calling assignment operator!.

class GPoint
{
public:

    GPoint();
    virtual ~GPoint();
    GPoint(double p_dX, double p_dY);
    GPoint (const GPoint &Source);
    GPoint& operator = (const GPoint &point);

public:
    double c_y;
    double c_x;


};

class GCircle//:public GShape
{

public:
    GCircle();
    GCircle(GPoint p_point, double p_dRadius);
    ~GCircle(){}


    operator GPoint&();
    operator double&();

    double& GetRadius() const ;
    GPoint  GetCentre() const {return c_Centre;}  //Return copy Not a reference 

public:
    double  c_dRadius;
    GPoint  c_Centre;
};


Dlg::ButtonClick()
{
    GPoint Point1(10,2);
    GCircle circle(Point1, 100);//100 is the radius.

  **GPoint &Centre = circle.GetCentre();**   //is this reference safe/valid or invalid

}

Upvotes: 6

Views: 372

Answers (5)

That code is not valid C++ (even if VS accepts it), as you cannot bind a non-const reference to an rvalue (the temporary returned by the function).

As of the particular question of performance, and considering that you were binding a const reference, there is no advantage at all. The compiler will create an unnamed variable in the calling function and then bind the reference to that, so the copy is performed anyway.

To clarify a bit on the copy is performed anyway, the copy will or will not be performed depending on whether the compiler can elide it, and in general it can. All compilers I know, implement the calling convention for your object (too large for registers) by allocating the object in the caller stack and passing a pointer to that uninitialized memory to the function. The function in turn uses that memory to create the returned object, avoiding the copy from the returned object to the variable in GPoint p = circle.GetCentre();, performing a single copy from circle.c_Centre to p (or to the unnamed variable if you bound a reference to constant).

Upvotes: 6

Loki Astari
Loki Astari

Reputation: 264451

No.

It should not even compile in the current state.

circle.GetCentre();

This returns an object.
Since you do not assign it to the variable it is an unamed temporary object.

temporary can not be bound to a reference (though they can be bound to a const refererence).

// This should be a compiler error
GPoint& Centre = circle.GetCentre();

// This should compile
GPoint const& Centre = circle.GetCentre();   

When you bind a temporary to a const reference it's lifespan is extended to the life of the reference.

Upvotes: 3

Mordachai
Mordachai

Reputation: 9662

There's nothing wrong with returning a reference to a member, just so long as you don't delude yourself that you can use that reference beyond the scope of the class object from which it came.

Ex:

GPoint Point1(10,2);
{
    GCircle circle(Point1, 100);//100 is the radius.

    GPoint & centre = circle;   // valid for lifetime of circle.

    ... // do stuff with centre
}
// centre no longer pointing at valid object, but then, centre is itself out of scope, so no issue!

Upvotes: 0

matthias
matthias

Reputation: 2499

No, it's not safe or valid. GCircle::GetCentre() returns-by-value, so the memory where the returned value is temporarily stored will be invalid at the end of the statement. Assigning a piece of data to a reference variable really only stores a pointer to the original's address in memory. Once that memory is invalid, Centre could be referencing any memory of any type, and will blindly treat it like a GPoint.

To save a value returned-by-value, you would need to say GPoint Centre = circle.GetCentre();. If you indeed want a reference to circle's c_Centre member, you should rewrite GetCentre() as such:

GPoint& GetCentre() const {return c_Centre;}

Furthermore, since you probably don't want people outside of circle to change its centre, you should probably return it as a const GPoint&:

const GPoint& GetCentre() const {return c_Centre;}

This will cause anyone looking at the new Centre local variable to think its const, without changing the way circle views the same piece of data.

Upvotes: 2

jrok
jrok

Reputation: 55395

No, it is not valid, GetCentre() returns a temporary and references cannot be bind to rvalues. You can, however, bind it to const reference:

const GPoint& centre = circle.GetCentre();

In this case, the "lifetime" of the rvalue is extended so the const reference remains valid while it is in scope.

Upvotes: 1

Related Questions