C++: как работать с объектом const, который необходимо изменить?

у меня есть место в коде, который говорил

const myType & myVar = someMethod();

проблема в том, что:

  • метода someMethod() возвращает const myType

  • мне нужно иметь возможность изменить myVar позже, назначив значение по умолчанию, если объект находится в недопустимом состоянии. Поэтому мне нужно сделать myVar быть константным.

    1. Я предполагаю, что мне нужно сделать myVar Не-ссылкой, да? Например. myType myVar?

    2. каков "правильный" способ c++ делать это const-to-nonconst? Статический слепок? Лексические гипсе? Что-то еще?

у меня может быть доступ к лексическому составу boost, поэтому я не против этого варианта, но я бы предпочел не-boost решение, а если это заканчивается, мне не разрешено использовать boost.

спасибо!

7 ответов


Я бы не использовал решения const_cast, и копирование объекта может не сработать. Вместо этого, почему бы не условно назначить другую ссылку const? Если myVar действителен, назначьте это. Если нет, назначьте значение по умолчанию. Затем код ниже может использовать эту новую ссылку const. Один из способов сделать это-использовать условное выражение:

const myType& myOtherVar = (myVar.isValid() ? myVar : defaultVar);

другой способ-написать функцию, которая принимает ссылку const (myVar) и возвращает myVar или defaultVar, в зависимости от действительности myVar, и назначьте возвращаемое значение от этого myOtherVar.

третий способ - использовать указатель const, указывая его на адрес myVar или адрес объекта по умолчанию.


вам, вероятно, не нужен никакой гипс. Если вы можете скопировать T, тогда вы также можете скопировать T const, патологические случаи исключены. Копия T const не нужно .

myType myVar = someMethod(); // Creates a non-const copy that you may change.

const_cast<type without const>()

но,someMethod() на самом деле вернуть const myType? Если это так, вы ссылаетесь на временное-оно будет уничтожено, и ваша ссылка будет плохой. Изменить myVar для non-ref (так что он копирует) - нет необходимости объявлять его const в этом случае. Или, если someMethod() возвращает ссылку, используйте const_cast если вы должны (но вы меняете то, что someMethod мысль не изменится).


нет способа "C++" (не только для этого, но и для чего угодно).

плохой способ-использовать const_cast, но тогда поведение будет неопределенным (читайте: Не делайте этого).

что вы должны сделать, это скопировать объект, а затем изменить копию. Это единственное правильный способ работы с неизменяемыми объектами.


попробуйте следующее

myType& mutableMyVar = const_cast<myType&>(myVar);

В общем, удаление const-плохая идея. Метод caller вернул вам ссылку на переменную, которая, по его мнению, будет рассматриваться как const. Если вы нарушите это предположение, удалив const и изменив переменную, вы можете поместить любой объект в допустимое состояние.

это может быть законно в вашем конкретном случае, но в целом этого следует избегать


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

но я думаю, вам было бы лучше понять, почему функция возвращала тип const в первую очередь. Была бы причина, по которой он был объявлен const. Если вы очень уверены, что это то, что вы хотели, вы всегда можете const_cast прочь constness так:

T obj1 = const_cast<T&> (obj); 

каков "правильный" способ c++ делать это const-to-nonconst? Статический слепок? Лексические гипсе? Что-то еще?

нет никакого способа C++. По той или иной причине автор этого класса решил, что вы не сможете изменить экземпляр с помощью этого метода.

Если бы Вы были автором, вы могли бы заставить его вернуть ссылку non-const. Но они все еще подозрительны, если только класс действительно не имеет права скрывать это от вас (e.g нравится вектор не скрывает что он держит для вас, и просто скрывает как он содержит материал для вас).

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

class BadPosition
{
    int x, y;
 public:
    int& get_x() { return x; }
    int& get_y() { return x; }
    //...
};

BadPosition p;
p.get_x() += 1;
p.get_y() += -1;

class BetterPosition
{
    int x, y;
 public:
    void move(int x_inc, int y_inc) { x += x_inc; y += y_inc; }
    //...
};

BetterPosition p;
p.move(1, -1);

Если вам нужно это, чтобы поместить класс В допустимое состояние позже, тогда, возможно, подумайте о том, чтобы сделать его конструктор. Если вы не можете этого сделать, наименее обеспечьте метод Init (), чтобы не заставлять такой сложный класс полностью полагаться на внешнее манипулирование во что-то полезное.

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

X x;
...
Y y = x.get();
y.modify();
x = X(y);

Edit: Итак, класс возвращается по значению? В этом случае не должно быть никакого способа измените экземпляр в классе, так как все, что вы получаете, это копия в первую очередь. Вы можете ссылаться на это с помощью ссылки const, но даже если вы отбрасываете constness из этой ссылки, вы все равно ссылаетесь на временное.

мой ответ выше предполагал, что он вернул ссылку const, так как это казалось бы более разумным (я не видел, чтобы люди часто возвращались const значение, хотя, вероятно, есть те, кто категорически не рекомендую).