当std :: vector push_back()时,具有引用成员的对象

时间:2018-09-10 23:43:29

标签: c++

#include <iostream>
#include <vector>


class myClass {
public:
    double a;
    double& ref;
    myClass() : ref(a)
    {
        a = 1;
    }
    ~myClass() {}
};

using namespace std;

int main()
{
    vector<myClass> myVector;
    int nIter = 5;
    while (nIter--) {
        myVector.push_back(myClass());
    }
    return 0;
}

嗨。

我有myClass,我想将myClasses推回去,然后将它们组合到一个向量中。 但不幸的是, 我必须在myClass中使用引用。 问题是当临时对象销毁时,引用变为无效,并且向量包含其引用无效的对象。 经过研究,我能够看到那些引用变量指向(引用)相同的内存。 我想找到每个向量元素的引用成员变量引用每个向量元素的a(成员变量)的方式。 有什么办法可以做到这一点..?

enter image description here

  • 加法 我想进一步描述我的情况。 我有一个中型项目。在那里,用户可以选择在我的算法中使用成员变量中的哪个变量。所以我制作了使用ref变量的脚本,以便可以根据选项进行更改。 我希望我的解释很清楚。

1 个答案:

答案 0 :(得分:2)

之所以会出现这种现象,是因为您正在将'ref'成员初始化为堆栈中的值,然后默认的复制构造函数会将其复制到向量中。

例如,在调试器中,给ref的值是:

+       &myVector[1].ref    0x00eff80c {2.0000000000000000} double *
+       &myVector[1]    0x00126940 {a=2.0000000000000000 ref=2.0000000000000000 }   
+       myVector    { size=0x00000002 } std::vector<myClass,std::allocator<myClass> >
+       &nIter  0x00eff8f0 {0xffffffff} int *

您可以看到myVector[1].ref不在您期望的myVector[1]内部,并且实际上位于堆栈中。您可以看到nIter和ref仅相距57个字节:

&nIter - (int*)&myVector[0].ref 57

如果您想了解隐式发生的情况,可以删除副本构造函数:

myClass(myClass const &rhs) = delete;

在myClass内部,您会在push_back上收到错误消息。

另一种选择是编写自己的副本构造函数:

myClass(myClass const &rhs) : ref(a) {
  a = rhs.a;
}

如果您对此进行调试,则会看到值正确,并且每个引用的内存位置现在都位于myClass对象的范围之内。

最后,您也许可以使用emplace_back代替push_back,这将直接在向量的内存中构造myClass而不是调用复制ctor,尽管我不建议这样做因为它留下了这个引用复制错误。

如果走复制ctor路线,也不要忘记赋值运算符: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

例如

myClass baz;
baz = myVector[0];

这将调用operator =而不是复制ctor。如果您声明副本ctor,我的编译器(最新的Visual Studio c ++)会自动删除operator =,因此可以捕获此错误,但是编译器可能不会。