【问题标题】:Why don't reference members refer the assigned variable on nested vectors? What's a proper way to declare an alternative way to access a class member?为什么引用成员不引用嵌套向量上的分配变量?什么是声明访问类成员的替代方法的正确方法?
【发布时间】:2021-08-16 07:54:03
【问题描述】:

我想声明一种访问类成员(特别是数组位置)的替代方法,如

class Foo {
    int a[2];
    int &a_first = a[0];
};

这样对Foo 实例中的a_first 的任何访问在所有目的上都等同于访问同一实例的a[0]

上面的代码可以像我预期的那样处理类的单个实例和单个向量,但是在嵌套向量上使用时,引用地址与成员地址不同:

#include <iostream>
#include <vector>

class A {
public:
    int m;
    int &mref = m;
};

int main() 
{
    A a;
    std::cout << (&a.m == &a.mref) << '\n'; // output: 1

    std::vector<A> av1(1);
    std::cout << (&av1[0].m == &av1[0].mref) << '\n'; // output: 1

    std::vector<std::vector<A>> av2(1, std::vector<A>(1));
    std::cout << (&av2[0][0].m == &av2[0][0].mref) << '\n'; // output: 0

    return 0;
}

我认为引用变量充当其分配变量的别名,并在编译时解析,而不是在运行时分配任何实际内存,这与指针不同。为什么这与上面显示的行为不一致?实现我想要的别名的正确方法是什么?

【问题讨论】:

  • 尽管问题已回答,但值得一提的另一点。也就是说 std::vector 不执行深度复制,因此您的引用保持不变,因此为了复制引用,您可以覆盖复制构造函数。但请记住,大多数容器是 std 不执行深度复制。因此,如果您的项目中有指针,则应注意这种行为。

标签: c++ class vector reference member


【解决方案1】:

上面的代码按我的预期工作

其实没有:

class A {
public:
    int m{};
    int &mref = m;
};

int main() 
{
    A a;
    A a2 = a;
    std::cout << (&a2.m == &a2.mref) << '\n'; // output: 0
};

只能在初始化时绑定引用。复制将复制值,而不是重新绑定引用。因此,A 类型对象的任何副本都会弄乱您的参考。这就是嵌套向量示例中发生的情况。您不需要嵌套向量即可看到这一点。尝试推入vector&lt;A&gt;,矢量将不得不调整大小,并且在调整大小期间将复制其元素,弄乱您的参考。

我认为引用变量充当其分配变量的别名...

是的

...并且在编译时被解析,而不是在运行时分配任何实际内存,这与指针不同。

并非总是如此。您不能总是在编译时解析引用,在这种情况下,引用实际上将在后台使用指针实现。

可能的解决方案:

  • 使用std::reference_wrapperthe copy assignment operator 重新绑定引用,但您需要为您的类实现自定义复制构造函数/赋值:

    class A {
    public:
        int m{};
        std::reference_wrapper<int> mref = m;
    
        A() = default;
    
        A(const A& other) noexcept
            : m{other.m},
              mref{m}
        {}
    
        A& operator=(const A& other) noexcept
        {
            m = other.m;
            mref = m;
    
            return *this;
        }
    };
    
  • 使用返回变量引用的方法

    class A {
    public:
        int m{};
    
        int& mref() { return m; }
        const int& mref() const { return m; }
    };
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-14
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多