【问题标题】:Why is constness not enforced for pointers?为什么不对指针强制执行 constness?
【发布时间】:2019-03-07 12:54:55
【问题描述】:

考虑以下代码sn-p:

class A
{
public:

    void nonConstFun()
    {

    }
};

class B
{
private:

    A a_;
    A * pA_;

public:

    void fun() const
    {
        pA_->nonConstFun();
        //a_.nonConstFun(); // Gives const related error
    }
};

int main()
{
    B b;
    b.fun();
}

在这里,我希望编译器会因为在 B::fun() 内调用 A::nonConstFun() 缺乏常量而失败,而不管 A 对象的类型如何。

但是编译器会抱怨对象,而不是指针。为什么? 我在 Windows 10 上使用 VS2017。

【问题讨论】:

  • 一个const成员函数意味着它不会改变这个对象的内部状态,而对象的引用可能会改变。

标签: c++ pointers constants transitive-const


【解决方案1】:

其他答案解释了 T* const vs T const * 这是正在发生的事情。但重要的是要理解这不仅仅是语法的含义。

当您在结构中拥有T* 时,指针位于对象内部(对象布局的一部分),但指向的对象在物理上位于结构外部。这就是为什么带有 T* 成员的 const 对象不允许修改指针,但允许修改指向的对象 - 因为物理上指向的对象在封闭对象之外。

并且由程序员决定指向的对象是逻辑上封闭对象的一部分(因此应该与封闭对象共享常量)还是逻辑上是外部实体。前者的示例包括std::vectorstd::string。后者的示例包括std::spanstd::unique_ptrstd::shared_ptr。如您所见,两种设计都很有用。

C++ 的缺点是它没有提供一种简单的方法来表达如上所述的逻辑常量(您对代码的实际期望)。

这是已知的,为了这个确切的目的,有一个尚未标准的实验班propagate_const

std::experimental::propagate_const 是一个 const-propagating 包装器 指针和类指针对象。它将包装的指针视为 通过 const 访问路径访问时指向 const 的指针,因此 名字。

struct B
{
    A a_;
    std::experimental::propagate_const<A *> pA_;

   void fun()
    {
        pA_->nonConstFun(); // OK
    }
    void fun() const
    {
        // pA_->nonConstFun(); // compilation error
    }
};

【讨论】:

    【解决方案2】:

    强制执行的。

    如果你尝试改变指针,编译器不会让你。

    然而,指针所指的是不同的对话。

    记住,T* constT const* 不是一回事!

    您可以通过将其设为 A const* 或简单地以适当的方式编写函数来保护它。

    【讨论】:

    • 我经常发现像cdecl.org 这样的工具对于确保我阅读const 的方式与编译器阅读它的方式相同。
    • @bta 对于更复杂的类型,这当然很有帮助,尽管通常您希望避免使用这些类型,或者至少以现代清晰的方式拼写它们(制作别名,并使用 usingtypedef!)。对于像这样的简单案例,您应该能够本能地阅读它。请记住,const 适用于左侧,除非那里没有任何东西,在这种情况下它适用于右侧。
    • 我认为如果 const 对象具有指针成员,您可以从本质上更改它的状态并不好。 std::experimental::propagate_const 似乎有助于解决这个问题。
    猜你喜欢
    • 2011-08-22
    • 2014-06-16
    • 2023-04-01
    • 2016-04-13
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    相关资源
    最近更新 更多