Ссылочная переменная в C ++ - PullRequest
       0

Ссылочная переменная в C ++

6 голосов
/ 07 декабря 2011

Предположим, у меня есть следующий фрагмент кода для GPoint, в котором есть конструктор копирования, оператор присваивания и деструктор.То же самое для GCircle и имеет функцию с именем GetCentre(), которая возвращает копию объекта Gpoint (Centre).

В main или ButtonClick(), как показано ниже, безопасно / допустимо звонить GPoint &Centre = circle.GetCentre()?Делая это (если допустимо), мы бы сэкономили время вызова оператора присваивания!.

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

}

Ответы [ 5 ]

6 голосов
/ 07 декабря 2011

Этот код не является допустимым C ++ (даже если VS принимает его), так как вы не можете привязать неконстантную ссылку к rvalue (временному, возвращаемому функцией).

Что касается конкретного вопроса производительности, и, учитывая, что вы связывали константную ссылку, никакого преимущества нет вообще. Компилятор создаст неназванную переменную в вызывающей функции, а затем свяжет ссылку на нее, так что копирование выполняется в любом случае.

Чтобы уточнить, что копирование выполняется в любом случае , копия будет выполняться или не будет выполняться в зависимости от того, может ли компилятор ее исключить, и, в общем, может. Все известные мне компиляторы реализуют соглашение о вызовах для вашего объекта (слишком большое для регистров), выделяя объект в стеке вызывающих и передавая указатель на эту неинициализированную память функции. Функция, в свою очередь, использует эту память для создания возвращенного объекта, избегая копирования из возвращенного объекта в переменную в GPoint p = circle.GetCentre();, выполняя единственную копию от circle.c_Centre до p (или к неназванной переменной, если вы привязали ссылку к константе).

3 голосов
/ 07 декабря 2011

номер

Он даже не должен компилироваться в текущем состоянии.

circle.GetCentre();

Возвращает объект.
Поскольку вы не присваиваете его переменной, это временный объект без имени.

Временный нельзя привязать к ссылке (хотя они могут быть привязаны к константной ссылке).

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

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

Когда вы связываете временную ссылку с константной ссылкой, срок ее службы увеличивается до срока действия ссылки.

2 голосов
/ 07 декабря 2011

Нет, это не безопасно и не действует. GCircle::GetCentre() возвращает значение по значению, поэтому память, в которой возвращенное значение временно сохраняется, будет недействительной в конце оператора. Присвоение части данных ссылочной переменной действительно сохраняет в памяти только указатель на адрес оригинала. Если эта память недействительна, Centre может ссылаться на любую память любого типа и будет слепо рассматривать ее как GPoint.

Чтобы сохранить значение, возвращаемое по значению, вам нужно будет сказать GPoint Centre = circle.GetCentre();. Если вы действительно хотите получить ссылку на circle участника c_Centre, вам следует переписать GetCentre() следующим образом:

GPoint& GetCentre() const {return c_Centre;}

Кроме того, поскольку вы, вероятно, не хотите, чтобы люди за пределами circle изменили его центр, вам, вероятно, следует вернуть его как const GPoint&:

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

Это заставит любого, кто смотрит на новую локальную переменную Centre, думать, что она const, без изменения способа, которым circle просматривает один и тот же фрагмент данных.

1 голос
/ 07 декабря 2011

Нет, это недопустимо, GetCentre () возвращает временное значение, и ссылки не могут быть привязаны к значениям. Однако вы можете привязать его к константной ссылке:

const GPoint& centre = circle.GetCentre();

В этом случае «время жизни» значения r увеличивается, поэтому ссылка на const остается действительной, пока она находится в области видимости.

0 голосов
/ 07 декабря 2011

Нет ничего плохого в том, чтобы возвращать ссылку на член, только если вы не вводите себя в заблуждение, что можете использовать эту ссылку за рамками объекта класса, из которого она получена.

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!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...