Как инициализировать ссылку на объект, если ссылка является членом класса?

Допустим, Class содержит ссылку с именем matrix_:

Класс.h

class Class
{
Matrix& matrix_;
}

Класс.cpp

Class::Class() : matrix_(Matrix())
{
}

Я получаю сообщение об ошибке: недопустимая инициализация неконстантной ссылки типа «Матрица» из временной ссылки типа «Матрица».

Я вижу, что проблема в том, что временный объект исчезнет, ​​а ссылка будет указывать на NULL. Как я могу создать постоянный объект для ссылки? Я хочу использовать ссылку, потому что этот член должен быть постоянным.


person problemofficer    schedule 15.11.2010    source источник
comment
вы не можете привязать rvalue к неконстантной ссылке   -  person erjot    schedule 15.11.2010


Ответы (4)


Class::Class() : matrix_(Matrix()) пытается установить ссылку, указывающую на временный объект, что является недопустимым.

ну, есть случай с постоянными ссылками и временной привязкой, но серьезно, не лезьте туда.

Похоже, вам просто нужно использовать агрегацию:

class Class
{
const Matrix matrix_;
};

И список инициализаторов:

Class::Class() : matrix_() /* or any params to the constructor if you need them */
{
}
person Kos    schedule 15.11.2010
comment
+1 за простоту :) Возможно, вы захотите добавить точку с запятой после определения класса (я бы сделал это за вас, но недостаточно репутации). Похоже на распространенную ошибку из исходного вопроса... - person Stuart Golodetz; 15.11.2010
comment
Я забыл, что могу сделать это так просто. - person problemofficer; 16.11.2010
comment
@sgolodetz, Совершенно верно, сразу исправлю для ясности. :) - person Kos; 16.11.2010

Ссылка Matrix должна предоставляться в качестве аргумента всех конструкторов класса.

class Class
{
  Matrix & matrix_;
public:
  Class(Matrix & matrix);
};

Class::Class(Matrix & matrix) : matrix_(matrix)
{
}

Обратите внимание, что хотя ссылка будет константой (ссылки C++ являются постоянными указателями), Matrix, на который ссылаются, не будет, если только вы не добавите спецификатор const.

person bltxd    schedule 15.11.2010
comment
matrix_ является частным, так что, к сожалению, это не вариант - person problemofficer; 16.11.2010

Проблема в том, что ссылки не предназначены для этого. Их следует использовать больше как «псевдоним» для чего-то уже существующего. Будь то анонимный объект стека (жизнь которого контролируется областью действия кода) или объект кучи с собственным уже существующим указателем. В вашем случае вы пытаетесь использовать ссылку только для ее постоянного свойства, но забываете, что это больше, чем постоянный указатель.

Подходящим решением будет использование постоянного указателя и размещение нового объекта в куче следующим образом:

Класс.h

class Class
{
Matrix* const matrix_;
}

Класс.cpp

Class::Class() : matrix_(new Matrix())
{
}
person problemofficer    schedule 15.11.2010
comment
Я ответил на свой вопрос, потому что он пришел ко мне, когда я думал над этим вопросом, и я хотел поделиться этим с другими, столкнувшимися с той же проблемой. Хотя я не уверен, что это правильно. - person problemofficer; 15.11.2010
comment
Или просто создайте его как значение и забудьте об косвенности. - person Peter Alexander; 15.11.2010

Вам не нужно использовать ссылку, чтобы этот член был постоянным. Вы можете использовать boost::scoped_ptr<const Matrix>.

class Class
{
public:
    Class();
private:
    boost::scoped_ptr<const Matrix> _matrix;
}

Class::Class() : _matrix(new Matrix)
{
}
person Steve Townsend    schedule 15.11.2010
comment
Мне любопытно, почему вы предлагаете boost::scoped_ptr вместо std::auto_ptr? - person Flexo; 15.11.2010
comment
@awoodland - чисто привычка, редко пользуюсь auto_ptr - person Steve Townsend; 15.11.2010
comment
Я волновался, что есть веская причина предпочесть его auto_ptr, которого я раньше не замечал. - person Flexo; 15.11.2010
comment
@awoodland - я думаю, что мое отвращение к auto_ptr связано с использованием версии VC6 (из которой вы можете сделать vector). - person Steve Townsend; 15.11.2010
comment
@awoodland: семантика немного отличается, и использование scoped_ptr гарантирует, что не будет сгенерировано operator= (если вы используете std::auto_ptr, а затем пишете Class a, b; a = b;, компилятор с радостью сгенерирует оператор присваивания, который освобождает внутренний указатель в a, а затем передает право собственности с b по a, оставив b с пустыми руками. - person David Rodríguez - dribeas; 15.11.2010
comment
@david, значит, это похоже на идиому const auto_ptr? - person Flexo; 15.11.2010
comment
@awoodland: Не совсем, это отключает странное поведение непреднамеренных копий, но позволяет вам reset указать элемент (при необходимости) или swap указатель. В большинстве случаев мне вообще не нужен reset, но возможность swap содержимого двух объектов является простым шагом к строгой гарантии исключений (идиома для гарантий исключений: работать в стороне с копией, если удалось поменять местами содержимое. Оригинал объект изменяется только через swap, что является операцией без броска). - person David Rodríguez - dribeas; 16.11.2010