有没有一种有效的方法来引用常量而不是只读常量?

Is there an efficient way to make reference to constants actually const instead of read only?

我们来看下面的C++代码:

#include <iostream>

int main()
{
    int z = 2;

    class A {
        public:
        const int & x;
        A(const int & x) : x(x) {}
        void show(){
            std::cout << "x=" << this->x << std::endl ;
        }
    } a(z);

    a.show();
    z = 3;
    a.show();
}

程序打印:2 和 3

它清楚地表明,虽然在内部 class A x 无法修改,它仅表示它是只读的,因为我可以从外部更改它的值。

当然我可以把它做成一个副本存储在classA里面,但是我想知道是否有(或者是否有建议?)对class说的方式A 成员 x 将真正保持不变,而不仅仅是只读,意味着外部代码不会更改它的承诺?

在我看来,它似乎与 C restrict 关键字的含义有关,但我还没有听说过任何此类 C++ 功能。你呢?

您正在寻找 D 的 immutable 关键字,它作为该语言中的一个新概念被引入正是因为不幸的是,答案是否定的:它在 C++ 中不存在。

C++ 中的 Constness 并不意味着不变性,而是指有问题的变量是 read-only。它仍然可以被程序的其他部分修改。我理解你关于是否可以在不知道调用者在做什么的情况下在被调用函数中强制执行真正不变性的问题。

当然你可以创建一个模板包装器class来完成任务:

template <typename T>
class Immutable
{
public:
    template <typename ...Args>
    Immutable( Args&&...args ) 
        : x( std::forward<Args>(args)... )
    {}

    operator const T &() const
    {
        return x;
    }

private:
    const T x;
};

只要您不使用 reinterpret_castconst_cast,当您用 Immutable<T>.

包装它们时,您将拥有真正不可变的对象

但是,如果您有对某个对象的常量引用,则无法判断程序的其他部分是否具有对该对象的 non-constant 访问权限。事实上,底层对象可能是一个全局变量或静态变量,您可以 read-only 访问它,但您调用的函数可能仍会修改它。

Immutable<T> 对象不会发生这种情况。但是,使用 Immutable<T> 可能会给您带来额外的复制操作。您需要判断自己是否可以忍受,以及成本是否值得收益。

函数需要 const Immutable<Something> & 而不是 const Something & 作为参数会影响调用代码。可能会触发复制操作。或者,您可以要求 Immutable<Something> & 而没有 const。这样就不会触发意外复制,但调用代码必须传递对 Immutable<Something> 对象的引用。这是正确的,因为如果调用者收到一个 const & 作为参数,那么调用者不知道该对象是否可能被程序中的其他人修改。调用者必须自己创建对象或需要将不可变对象作为引用传递给它。

你原来的问题

这是 Immutable<int> & 而不是 const int & 的原始问题。

#include <iostream>

int main()
{
    Immutable<int> z = 2;

    class A {
        public:
        const Immutable<int> & x;
        A(Immutable<int> & x) : x(x) {}
        void show(){
            std::cout << "x=" << this->x << std::endl ;
        }
    } a(z);

    a.show();
    //z = 3; // this would fail
    a.show();
}

另一个例子

它是这样工作的:如果你写

void printAndIncrementAndPrint( int & i1, const int & i2 )
{
    std::cout << i2 << std::endl;
    ++i1;
    std::cout << i2 << std::endl;
}

int main()
{
    int i = 0;
    printAndIncrementAndPrint( i, i );
}

然后它将打印

0
1

进入控制台。如果将 printAndIncrementAndPrint() 的第二个参数替换为 const Immutable<int> & i2 并保持其余不变,则会触发副本并打印

0
0

到控制台。在不使用 const_castreinterpret_cast 破坏类型系统的情况下,您不能将 Immutable<int> 传递给函数,将 int & 传递给相同的基础数据。

常量是实际变量的一个属性。

术语 const int& x 仅表示 "x is a reference to an int which it will not modify",当然编译器会强制执行此操作。

如果您希望 x 所指的实际变量是常量,只需这样声明即可:

#include <iostream>

int main()
{
    const int z = 2;    // declared const. Nothing may ever modify it

    class A {
    public:
        const int & x;
        A(const int & x) : x(x) {}
        void show(){
            std::cout << "x=" << this->x << std::endl ;
        }
    } a(z);

    a.show();
    z = 3;        // this is a logic error, caught by the compiler.
    a.show();
}

编译正确产生错误:

./const.cpp:41:7: error: read-only variable is not assignable
    z = 3;
    ~ ^
1 error generated.

我认为这是程序员的设计问题,而不是语言。 const 变量意味着对于该变量的任何用户,他们不应更改该变量的值。我们的编译器足够聪明,可以帮助我们确保这一点。所以 Az 的用户,如果你想让 A 知道 A::x 引用 const 变量,那么你应该 z一个const intconst reference只是为了保持用户和提供者之间的合同。