В настоящее время я пишу код, в котором у меня есть пользовательские типы дескрипторов.Рассматриваемый код выглядит примерно так:
struct SegmentData
{
//...
};
class SegmentHandle
{
public:
SegmentHandle(Path * _path, int _idx);
void setPosition(float _x, float _y);
float positionX() const;
float positionY() const;
private:
Path * m_path;
int m_index;
};
class Path
{
public:
SegmentHandle segmentHandle(int _idx) const
{
// Path object itself can never be const so this should be fine
return SegmentHandle(const_cast<Path*>(this), _idx);
}
private:
std::vector<SegmentData> m_segmentData;
};
Path * path = createPath();
//...add some segments
SegmentHandle seg = path.segmentHandle(3);
seg.setPosition(100, 30);
//...
С точки зрения правильности const это не очень хорошо, так как мы можем изменить данные Path
через SegmentHandle
, несмотря на то, что getter является const.Чтобы исправить это, я попытался использовать отдельные типы для const
и не const
дескрипторов (аналогично const_iterator
против iterator
в стандартной библиотеке), то есть:
template<class PT>
class SegmentHandleT
{
public:
SegmentHandleT(PT * _path, int _idx);
void setPosition(float _x, float _y);
float positionX() const;
float positionY() const;
private:
PT * m_path;
int m_index;
};
using SegmentHandle = SegmentHandleT<Path>;
using ConstSegmentHandle = SegmentHandleT<const Path>;
Хотя это выглядит нормально впростой пример, подобный этому, в реальной кодовой базе, где у вас есть несколько взаимодействующих типов дескрипторов, он значительно увеличивает сложность кода, вводит шаблоны, в которых они иначе не использовались бы / не нужны, и т. д. Это всерьез соблазняет меня придерживаться варианта 1 в техническом отношениифункция напрямую не изменяет базовый объект пути.Есть ли другие варианты для поддержания более высокого уровня const правильности в таком сценарии, где компромисс между сложностью кода и выгодами в реальном мире более сбалансирован?
Спасибо!