Только сейчас заметил, что когда я пишу const type_shared или const type_shared&, то констатнтым является оболочка смартпойнтера, но не указатель, который она хранит.
Соответственно, решил, что следует определить два типа:
typedef boost::shared_ptr< type > type_shared;
typedef boost::shared_ptr< const type > type_shared_const;
Вопросы:
1) (глупый) Так все и делают?
2) Если у меня есть type_shared, а в функцию нужно передать type_shared_const, что при этом происходит? Неявное конструирование type_shared_const из type_shared? Дает ли это какой-то оверхед в runtime, или все разрешается в compile time?
I> Только сейчас заметил, что когда я пишу const type_shared или const I> type_shared&, то констатнтым является оболочка смартпойнтера, но не I> указатель, который она хранит.
Всё правильно. Когда ты вызываешь operator -> для смартпоинтера, тебе возвращается константный объект, у которого ты можешь вызывть лишь константные ф-ции. Это поведение соответствует обычному указателю на константный объект.
I> Соответственно, решил, что следует определить два типа:
Зачем?
Здравствуйте, ArtDenis, Вы писали:
I>> Только сейчас заметил, что когда я пишу const type_shared или const I>> type_shared&, то констатнтым является оболочка смартпойнтера, но не I>> указатель, который она хранит. AD>Всё правильно. Когда ты вызываешь operator -> для смартпоинтера, тебе возвращается константный объект, у которого ты можешь вызывть лишь константные ф-ции. Это поведение соответствует обычному указателю на константный объект.
I>> Соответственно, решил, что следует определить два типа: AD>Зачем?
Как это зачем? Чтобы пользоваться фичей "const" компилятора С++.
Здравствуйте, ArtDenis, Вы писали:
I>> Только сейчас заметил, что когда я пишу const type_shared или const I>> type_shared&, то констатнтым является оболочка смартпойнтера, но не I>> указатель, который она хранит. AD>Всё правильно. Когда ты вызываешь operator -> для смартпоинтера, тебе возвращается константный объект, у которого ты можешь вызывть лишь константные ф-ции. Это поведение соответствует обычному указателю на константный объект.
Здравствуйте, ArtDenis, Вы писали:
I>> Разве?
AD>Ошибся. Посыпаю голову пеплом
А вообще конечно полдянка получается. От константного умного указателя ожидаешь увидеть аналог обычного указателя на константный объект. А он тебе раз — подсовывает неконстантный...
Вообще-то большинство умных указателей соблюдают ту же семантику константности (а именно: shallow constness), что и глупый указатель. То есть, константность указателя и указуемого — ортогональны.
shared_ptr<T> принимает (в конструктор и оператор присваивания) любые shared_ptr<Y>, такие, что Y* можно неявно привести к T*
Поскольку T const* приводится к T*, то проблем не возникнет.
А если ты хочешь сделать deep constness — то изволь ручками (может быть, как обёртку над shared_ptr).
Вот только зачем она тебе нужна? Скажем, когда некоторый объект отдаёт наружу свои данные (накладывая собственную константность, естественно) — то достаточно написать пару get-функций.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Ignoramus, Вы писали:
К>Вообще-то большинство умных указателей соблюдают ту же семантику константности (а именно: shallow constness), что и глупый указатель. То есть, константность указателя и указуемого — ортогональны.
К>shared_ptr<T> принимает (в конструктор и оператор присваивания) любые shared_ptr<Y>, такие, что Y* можно неявно привести к T* К>Поскольку T const* приводится к T*, то проблем не возникнет.
А Вы случайно не путаете запись const T* и T* const? Первое означает константный объект, второе — константный указатель. Это мое замечание касается только формы записи, со смыслом вроде путаницы нет
К>А если ты хочешь сделать deep constness — то изволь ручками (может быть, как обёртку над shared_ptr).
А чем плох вариант, который я предложил? boost::shared_ptr< const type > ?
К>Вот только зачем она тебе нужна?
Я тоже задал себе этот вопрос — а зачем, действительно? Ответ такой: когда нужно не просто получить доступ к внутренним данным объекта (как в Вашем примере), а выдать наружу созданный объект (как в паттерне Builder), обернутый, естественно, в смарт-поинтер. Так вот, бывают ситуации, когда созданный объект должен быть const. Это можно себе представить (не является ли это плохим дизайном)? Думаю да, поправьте меня если я ошибаюсь.
К>Скажем, когда некоторый объект отдаёт наружу свои данные (накладывая собственную константность, естественно) — то достаточно написать пару get-функций.
А что делать, если в интерфейсе объекта есть также set(put)-функции? Если передавать объект без const, то клиент сможет их вызывать, а хотелось бы иметь возможность это запретить, когда нужно.
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, ArtDenis, Вы писали:
I>>> Разве?
AD>>Ошибся. Посыпаю голову пеплом
AD>А вообще конечно полдянка получается. От константного умного указателя ожидаешь увидеть аналог обычного указателя на константный объект. А он тебе раз — подсовывает неконстантный...
Да никакой подлянки:
type const * ~ smart_ptr<type const> — указатель на константу
type * const ~ smart_ptr<type> const — константный указатель
Так что всё логично