Влияет ли boost :: scoped_ptr на принцип логической константности? - PullRequest
3 голосов
/ 16 июля 2011

В boost :: scoped_ptr operator* и operator-> объявлены const функции, хотя они возвращают T& и T*, что потенциально позволяет клиентам изменять базовые данные.Это нарушает идею логического константности (Myers, Effective C ++)

Разве функции const не должны иметь сигнатуру?

const T& operator*() const;
const T* operator->() const;

Ответы [ 3 ]

6 голосов
/ 17 июля 2011

Фундаментальная проблема здесь заключается в том, что scoped_ptr объекты ведут себя больше как указатели, а не как объекты классов (даже если scoped_ptr экземпляры фактически являются объектами класса).

Классы интеллектуальных указателей, предоставляемые Boost, предназначены для максимально возможного сохранения семантики необработанных указателей при одновременном предоставлении дополнительных функций, таких как подсчет ссылок или (в данном случае) семантика RAII.

С этой целью operator*() и operator->() члены scoped_ptr записываются так, что его "поведение константности" по существу совпадает с таковым у необработанного указателя.

Рассмотрим эту ситуацию с «тупыми» указателями:

// Can change either Foo or ptr.
Foo* ptr;
// Can't change Foo via ptr, although ptr can be changed.
const Foo* ptr;
// Can't change ptr, although Foo can be changed via ptr.
Foo* const ptr;
// Can't change Foo or ptr.
const Foo* const ptr;

Аналоги scoped_ptr будут выглядеть так:

// Can change either Foo or ptr.
scoped_ptr<Foo> ptr;
// Can't change Foo via ptr, although ptr can be changed.
scoped_ptr<const Foo> ptr;
// Can't change ptr, although Foo can be changed via ptr.
const scoped_ptr<Foo> ptr;
// Can't change Foo or ptr.
const scoped_ptr<const Foo> ptr;

Способ написания операторов делает возможным приведенный выше фрагмент кода, даже если scoped_ptr на самом деле не является необработанным указателем.

Во всех случаях код должен иметь возможность разыменования ptr. Делая операторы const, операторы разыменования / доступа к членам можно вызывать как для const, так и для не const scoped_ptr с.

Обратите внимание, что если пользователь объявит scoped_ptr<Foo>, он будет иметь следующие члены:

Foo& operator*() const;
Foo* operator->() const;

в то время как scoped_ptr<const Foo> будет иметь следующие члены:

const Foo& operator*() const;
const Foo* operator->() const;

Таким образом, поведение указателей на const -корректность фактически сохраняется таким образом.

Но не более того, иначе они не были бы умными указателями!

1 голос
/ 24 ноября 2011

В boost :: scoped_ptr operator * и operator-> объявлены как константные функции, хотя они возвращают T & и T *, что потенциально позволяет клиентам изменять базовые данные.

«Базовые данные» не являются частью значения интеллектуального указателя. Два (умных) указателя равны, если они указывают на один и тот же объект: a == b если &*a == &*b.

Это нарушает идею логического constness (Myers, Effective C ++)

Нет, это не так:

Значение логического умного указателя зависит только от того, на что он указывает.

Разыменование умного указателя не меняет того, на что он указывает.

Таким образом, разыменование умного указателя не меняет его логическое значение (или его состояние, если вы предпочитаете).

QED

0 голосов
/ 17 июля 2011

A scoped_ptr<T> похоже на T*. Это не похоже на T* const.

A scoped_ptr<T const> походит на T const* (который вы могли бы написать как const T*) и только тогда вы ожидаете, что operator* и operator-> вернут const вещи.

...