【问题标题】:Does boost::scoped_ptr violate the guideline of logical constnessboost::scoped_ptr 是否违反了逻辑常量的准则
【发布时间】:2011-10-06 19:22:32
【问题描述】:

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

const 函数不应该有签名吗?

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

【问题讨论】:

  • +1:好问题。你错了,但很好的问题。 (考虑T* const。)
  • "这违反了逻辑常数的概念",你认为它是如何违反逻辑常数的?

标签: c++ constants smart-pointers boost-smart-ptr


【解决方案1】:

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

Boost 提供的智能指针类旨在尽可能保留原始指针语义,同时提供引用计数或(在本例中)RAII 语义等附加功能。

为此,scoped_ptroperator*()operator->() 成员被写入,使其“常量行为”基本上与原始指针相匹配。

用“哑”指针考虑这种情况:

// 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;

运算符的编写方式使上述代码 sn-p 成为可能,即使 scoped_ptr 实际上不是原始指针。

在所有情况下,代码都需要能够取消引用ptr。通过使运算符const,可以在const 和非constscoped_ptrs 上调用取消引用/成员访问运算符。

请注意,如果用户声明 scoped_ptr&lt;Foo&gt;,它将具有以下成员:

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

虽然scoped_ptr&lt;const Foo&gt; 会有这些成员:

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

所以指针的 const-correctness 行为实际上是以这种方式保留的。

但不要再多了,否则它们就不是智能指针!

【讨论】:

  • 指针而不是对象”实际上指针对象
  • @curiousguy:这可能是真的(取决于您使用的“对象”的定义),但我进行区分是为了解释为什么智能指针的设计方式与尊重为 const 正确性。话虽如此,我已将其更改为“类对象”以避免更多误解。
  • 我的定义是 C++ 定义:一个对象是一个存储区域。 int 变量是一个对象。
  • 表现得更像指针而不是类对象”来表现“像类对象”是一个主观概念。一些类意味着具有价值语义,其他类具有引用语义。迭代器对它们所引用的数据具有引用语义 WRT。这是一个预期的类语义问题。
  • @curiousguy:所以?与本机指针相反,智能指针仍然是类对象,不是吗? OP 问题中的问题是为什么智能指针运算符以这种方式定义为常量,而不是说vector 的数组下标运算符。这是因为智能指针类应该像指针一样工作,这与 vectors 等其他类不同,它们本身就是值。
【解决方案2】:

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

“基础数据”不是智能指针值的一部分。如果两个(智能)指针指向同一个对象,则它们相等:a == b iff &amp;*a == &amp;*b

这违反了logical constness(Myers,Effective C++)的思想

不,它没有:

智能指针的逻辑值仅取决于它所指向的内容。

取消引用智能指针不会改变它指向的内容。

因此,取消引用智能指针不会更改其逻辑值(或您喜欢的状态)。

QED

【讨论】:

    【解决方案3】:

    scoped_ptr&lt;T&gt; 类似于T*。它不像T* const

    scoped_ptr&lt;T const&gt; 类似于T const*(您可以写成const T*)并且只有这样您才会期望operator*operator-&gt; 返回const 的东西。

    【讨论】:

      猜你喜欢
      • 2016-04-18
      • 2014-02-15
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-04
      • 2015-01-01
      • 1970-01-01
      相关资源
      最近更新 更多