Здравствуйте, johny5, Вы писали:
J>Интересно, почему константность объекта передаётся только на константность указателя но не на объект, на который указатель указывает.
J>
J>struct Test
J>{
J> int* value;
J>};
J>void f()
J>{
J> const Test t;
J> *t.value = 0;
J>}
J>
J>Выглядит как брешь в константности. J>Почему так было сделано?
потому что указатель и то, на что он ссылкается — вещи не обосо связанные.
у тебя тип, к оторому применяется const — это указатель (т.е. после этого ты не сможешь его перенацелить на другой объект). К константности указуемого объекта это не имеет никакого отношения.
>потому что указатель и то, на что он ссылкается — вещи не обосо связанные. >у тебя тип, к оторому применяется const — это указатель (т.е. после этого ты не сможешь его перенацелить на другой объект). К константности указуемого объекта это не имеет никакого отношения.
Это понятно, я немного о другом.
struct Test
{
int a;
};
void f()
{
const Test t;
t.a = 5; //низя
}
и
struct Test
{
int* a; //просто другой вид хранения значения int
};
void f()
{
const Test t;
*t.a = 5; //можно
}
с чего собственно? Почему такая разница?
Константность объекта подрузамевает константность всех его внутренностей. Не должно быть разницы, представлены они через указатель или по значению.
Здравствуйте, johny5, Вы писали:
>>потому что указатель и то, на что он ссылкается — вещи не обосо связанные. >>у тебя тип, к оторому применяется const — это указатель (т.е. после этого ты не сможешь его перенацелить на другой объект). К константности указуемого объекта это не имеет никакого отношения.
J>Константность объекта подрузамевает константность всех его внутренностей. Не должно быть разницы, представлены они через указатель или по значению.
Указатель и является внутренностями. Но не указуемое.
И вообще, что есть внутренность — вопрос скользкий.
Указатель — это не просто другой вид хранения.
Это — ссылочный тип, и то, что он ссылается на какой-то другой тип, означает лишь то, какой тип ты получишь в результате его разыменования. Т.е. единственная операция, которая обращается непосредственно к указуемому — это разыменование. Все остальные операции относятся именно к самому указателю как к ссылочному типу, а именно: любое изменение указателя (присваивание, инкремент и т.п.) означает перенацеливание.
И когда ты говоришь, что конкретный указатель является константой — ты просто гововришь, что все операции, которые его изменяют (т.е. перенацеливают), запрещены.
Разыменование указателя, очевидно, к изменяющим указатель операциям никак не относится.
С другой стороны, нет особых проблем дополнить операцию навешивания константности указателя навешиванием константности не только на сам указатель, но и на все его сколь угодно вложенные типы.
Единственная проблема (это так, навскидку) — что должно в результате давать снятие константности с указателя — неконстантный указатель на константу или на не-константу?
И чем же тогда является указатель на константу?
Или разрешим только два вида указателей — константный указатель на константу и неконстантный на неконстанту? Имхо, не слишком разумно.
Имхо, текущий подход наиболее логичен.
P.S. Если очень хочется протянуть const на все уровни многовложенного типа, воспользуйся boost::mpl.
Здравствуйте, johny5, Вы писали:
J>Интересно, почему константность объекта передаётся только на константность указателя но не на объект, на который указатель указывает.
J>
J>struct Test
J>{
J> int* value;
J>};
J>void f()
J>{
J> const Test t;
J> *t.value = 0;
J>}
J>
J>Выглядит как брешь в константности. J>Почему так было сделано?
Потому что int * — просто четыре (например) байта, которые можно интерпретировать как адрес чего-нибудь в памяти. Эти четыре байта менять нельзя, а то, куда они указывают, здесь ни при чем.
Здравствуйте, johny5, Вы писали:
J>Интересно, почему константность объекта передаётся только на константность указателя но не на объект, на который указатель указывает. J>Выглядит как брешь в константности. J>Почему так было сделано?
Эта штука называется поверхностной константностью (shallow constness). Известно ещё по феодализму: вассал моего вассала — не мой вассал.
Точно так же, как и копирование и уничтожение указателей — поверхностное.
При глубоком (deep) копировании — были бы два разных объекта
А при глубоком уничтожении — в момент выхода из области видимости был бы вызван деструктор объекта.
Поверхностное поведение является базовым.
Ведь, во-первых, никто не говорил, что указуемое всегда принадлежит указателю.
И во-вторых, глубину можно реализовать руками. А вот поверхностность — если глубина обеспечивается компилятором — без хака уже не получится.
А в тех случаях, когда тебе нужно реализовать глубокую константность или глубокое копирование — берёшь и пишешь адаптер.
Например,
Но, используя этот класс вместо голого указателя, ты подчёркиваешь, что указуемое находится в более тесной связи с этим указателем (и объектом, чьим членом указатель является).
брешь там или не брешь зависит от семантики класса. Надо управлять явно -- управляй явно, через адаптеры, через умные указатели и т. д.
J>Почему так было сделано?
Я думаю, что так было сделано, потому что так логичнее реализация. Грубо говоря такой подход гарантирует истинность следующего утверждения: "бинарное представление константного POD-типа, и только ононе может изменяться".
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском