boost::scoped_ptr是否违反了逻辑一致性原则?

Does boost::scoped_ptr violate the guideline of logical constness

本文关键字:一致性 原则 scoped ptr 是否 boost      更新时间:2023-10-16

在boost::scoped_ptr中,operator*operator->被声明为const函数,尽管它们返回T&T*,这可能允许客户端更改底层数据。这违反了逻辑一致性的思想(Myers, Effective c++)

const函数不应该有签名吗?

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

这里的基本问题是scoped_ptr对象的行为更像指针而不是类对象(尽管scoped_ptr实例实际上是类对象)。

Boost提供的智能指针类被设计成尽可能地保留原始指针语义,同时提供额外的功能,如引用计数或(在这种情况下)RAII语义。

为此,scoped_ptroperator*()operator->()成员被写入,使其"constness行为"本质上与原始指针相匹配。

考虑"哑"指针的这种情况:

// 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和非constscoped_ptr上调用解引用/成员访问操作符。

请注意,如果用户声明了一个scoped_ptr<Foo>,它将具有这些成员:

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

scoped_ptr<const Foo>则有以下成员:

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

因此,指针的const正确性行为实际上是这样保留的。

但是没有更多,否则它们就不是智能指针了!

在boost::scoped_ptr中operator*和operator->被声明为const函数,尽管它们返回T&和T*,这可能允许客户端更改底层数据。

"底层数据"不是智能指针值的一部分。如果两个(智能)指针指向同一个对象,则它们相等:a == b&*a == &*b

这违反了逻辑一致性的思想(Myers, Effective c++)

不,它没有:

智能指针的逻辑值只取决于它所指向的对象。

解除对智能指针的引用不会改变它指向的对象。

所以解引用一个智能指针并不会改变它的逻辑值(或者它的状态,如果你喜欢的话)。

QED

一个scoped_ptr<T>就像一个T*。它不像T* const .

一个scoped_ptr<T const>就像一个T const*(你可以写为const T*)和只有在你会期望operator*operator->返回const的东西。