Этот код демонстрирует проблему, которую я пытаюсь решить:Является ли это законным использованием reinterpret_cast, и если нет, то как это сделать?
#include <map>
class Point
{
public:
float m_x;
float m_y;
};
typedef std::set<Point *> PointSet;
typedef std::set<const Point * const> ConstPointSet;
float GetMinimumRange(const ConstPointSet &pointSet)
{
float minimumRange(0.0f);
// find the smallest distance between any pair of points in the set
return minimumRange;
}
float GetMinimumRangeWrong(const PointSet &pointSet)
{
PointSet::iterator first(pointSet.begin());
Point * point(*first);
point->m_x = 42.0f; // I want to prevent this
return 0.0f;
}
class PointSet_
{
public:
std::set<Point *> m_pointSet;
float GetMinumumRange() const
{
PointSet::iterator first(m_pointSet.begin());
Point * point(*first);
point->m_x = 42.0f; // I want to prevent this
return 0.0f;
}
};
void test()
{
PointSet myPointSet;
// Add some points to my set
// This fails because the compiler states it can't convert from PointSet to ConstPointSet.
//float minimumRange1(GetMinimumRange(myPointSet));
// reinterpret_cast<> is the only cast that works here, const_cast fails with the same
// complaint as the line above generates
ConstPointSet *myConstPointSet(reinterpret_cast<ConstPointSet *>(&myPointSet));
float minimumRange1(GetMinimumRange(*myConstPointSet));
float minimumRange2(GetMinimumRangeWrong(myPointSet));
}
Я хочу создать программу, которая принимает PointSet
, оценивает минимальный диапазон между любой парой Point
с в наборе, но она гарантирует что он не будет изменять переданный ему PointSet
каким-либо образом. Он не может изменить членов любого ссылочного Point
, он не может изменить указатели сами, и не может добавлять или удалять пользователей из множества
Вопрос заключается в том, что компилятор правильно рассматривает PointSet
и ConstPointSet
, как различные типы, потому что от разницы const
отборщиков внутреннего типа, и поэтому отказывается бросить между ними, хотя я только добавляю const
отборочные.
Я попытался создать класс, содержащий PointSet
, и создав функцию-член const, но даже там, где он допускает модификацию одного из внутренних Point
. По крайней мере, MSVC будет компилировать это без жалобы. Признаюсь, я был очень удивлен этим.
Единственный способ, которым я нашел, - это использовать reinterpret_cast<>
для преобразования указателя на PointSet
в указатель на ConstPointSet
. В стандарте отмечается, что reinterpret_cast<>
можно использовать для добавления квалификаторов const
, но применимо ли это в этом случае?
Если нет, есть ли способ сделать то, что я хочу? Я понимаю, что хорошая дисциплина кода может быть использована для обеспечения того, чтобы GetMinimumRange()
не изменял пройденный PointSet
, но я хотел бы получить там const
отборочных команд по двум причинам.
Они будут гарантировать, что если кто-либо изменяет
GetMinimumRange()
они не могут заставить его изменитьPointSet
.Это позволит компилятору оптимизировать вызов по телефону
GetMinimumRange()
. В отсутствие квалификаторовconst
на вызывающем сайте не могут быть сделаны допущения относительно значений, которые могут быть кэшированы по вызову, что может привести к избыточным выборкам данных.
Вам не нужно указывать указатель const, если контейнер является константой. Лично я просто передал копию контейнера и не имел указателей на элементы. Таким образом физически невозможно изменить значение, на которое указывают указатели, и вы можете просто позволить компилятору оптимизировать. – BWG
Это вызывает неопределенное поведение, нарушая строгий псевдоним. Типы, которые являются псевдонимами, являются 'set' и 'set ', которые не имеют отношения, если 'T' и' U' не идентичны –
@BWG удаление указателей будет работать, но это упрощенный пример кода для демонстрации пороблема. На практике «Point *» на самом деле указывают на Entites в игре. Использование набора <> из них, в отличие от набора указателей, будет иметь некоторые очевидные проблемы с производительностью. – dgnuff