【问题标题】:Access to reference in member variable discards constness访问成员变量中的引用会丢弃 constness
【发布时间】:2015-09-04 02:33:24
【问题描述】:

我在我的代码中围绕一个对象创建了一个包装器,该包装器应该修改对该对象的访问。我选择在这里使用对象进行测试,而不是使用具有相同功能的仿函数。基本上:包装器接收对对象的引用并转发对对象的所有索引访问(在一些可能的操作之后)
现在问题来了:访问器丢弃了被包装对象的常量。
最小的例子

struct Foo
{
    std::array<int, 2> data;
    const int& operator()(int idx) const{
        return data[idx];
    }
    int& operator()(int idx){
        return data[idx];
    }
};

struct Bar
{
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        return ref(idx);
    }
};

template< typename T >
void test(const T& data){
    data(1) = 4;
    std::cout << data(1);
}

void main(){
    Foo f;
    test(f);
    // Above call does not compile (as expected)
    // (assignment of read-only location)
    Bar b(f);
    test(b); // This does compile and works (data is modified)
}

将 Bar(包装器)的 () 运算符声明为“const”,我希望所有成员都可以访问“const”。所以应该不可能返回一个“int&”,而只能返回一个“const int&”

但是 gcc4.7 可以愉快地编译代码并且忽略 const。这是正确的行为吗?这是在哪里指定的?

编辑: 关于一个相关问题:如果在 Foo 中使用 typedef,例如:

struct Foo
{
    using Ref = int&;
    using ConstRef = const int&; //1
    using ConstRef = const Ref;  //2
    int* data; // Use int* to have same issue as with refs
    ConstRef operator()(int idx) const{
        return data[idx]; // This is possible due to the same "bug" as with the ref in Bar
    }
    Ref operator()(int idx){
        return data[idx];
    }
};

我注意到 //1 确实按预期工作,但 //2 没有。返回值仍然可以修改。他们不应该一样吗?

【问题讨论】:

  • 这是正确的行为。我不会回答这个问题,因为我不想费心从标准中查找引用,但基本上你的成员变量是引用本身,而不是被引用的 int。所以在你的 operator() const 中,引用成员“ref”没有被修改,只有它引用的 Foo。我认为 C++17 会有 const 传播指针和引用。

标签: c++ c++11 reference compiler-errors constants


【解决方案1】:

是的,这是正确的行为。 ref 的类型是 Foo &amp;。将const 添加到引用类型1 没有任何作用——无论如何,引用已经是不可变的。这就像拥有一个成员int *p。在const 成员函数中,其类型被视为int * const p,而不是int const * p

您需要做的是在const 重载中手动添加const(如果您想要它):

struct Bar
{
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        return const_cast<const Foo&>(ref)(idx);
    }
};

为了解决问题编辑:不,typedef 不一样。 const int &amp; 是对 (常量 int) 的引用。 const Ref是常量Ref,即常量(参考int);数学意义上的括号。


1 我说的是引用类型本身。不要与将 const 添加到引用所指的类型相混淆。

【讨论】:

  • “将 const 添加到引用类型没有任何作用” --- 你是什么意思? const int&amp;int&amp; 是不同的,不是吗?
  • @Petr const int&amp; 是对 const int 的引用,这与 constint 的引用不同。
  • @TartanLlama,好吧,我想我明白作者的意思,但我认为现在写的那句话无论如何都具有误导性......
  • @Petr 将const 添加到引用所指的类型,引用的类型。我会稍微改一下答案。
  • 所以基本上如果我在 Bar 中有一个 "Foo& ref" 和 "Foo inst",那么在 const 函数内部它会像 "Foo& const ref" 和 "Foo const inst" (="const Foo inst") 对吧?
【解决方案2】:

是的,这是预期的行为。原因是您的方法的 const 仅表示引用不会更改,而不是引用的对象。参考总是不变的,所以它总是正确的。用指针看一下这段代码:

int i;
struct Bar
{
    int* pi;
    Foo& ref;
    Bar(Foo& r):ref(r){}
    int& operator()(int idx) const{
        *pi = 4; // we can change pointed object
        pi = &i; // Compile error: we can't change the pointer.
        return ref(idx);
    }
}; 

【讨论】:

    猜你喜欢
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多