C++ 矢量 Push_back 产生奇怪的副作用

use*_*186 0 c++ pointers reference vector

当我使用STL向量存储类对象时,我观察到一个非常奇怪的副作用,其中push_back方法修改了现有数据!

基本上我有一个包含多个字段的类,如下所示:

class MyClass {
    MyClass(std::string s, int i) {
        StringValue = s;
        IntValue = i;
    }

    std::string StringValue;
    int IntValue;
}
Run Code Online (Sandbox Code Playgroud)

我有一个向量,其中包含指向 MyClass 对象的指针..然后我基本上推回对对象的引用:

std::vector<MyClass*> MyVector;
MyClass c1("CLASS 1", 1);
MyClass c2("CLASS 2", 2);

MyVector.push_back(&c1);
// Result:
// *MyVector[0]    ==>    ("Class 1", 1)



MyVector.push_back(&c2);
// Result:
// *MyVector[0]    ==>    ("Class 2", 2)   ??why 2??
// *MyVector[1]    ==>    ("Class 2", 2)
Run Code Online (Sandbox Code Playgroud)

你看到我得到的奇怪结果了吗?我在每个push_back语句之后设置了断点,并且发生了这种奇怪的事情。

第一个 Push_back 语句工作正常。但是第二个push_back语句修改了第一个元素的内容,这对我来说没有意义。

我假设它与我存储引用而不是向量内的实际对象有关......但我无法弄清楚出了什么问题。

我该如何处理这个问题?有什么见解吗?

谢谢


更新:

(简化代码)

MyClass c1("CLASS 1", 1);
MyClass c2("CLASS 2", 2);

MyClass temp;
while (int i=0; i<2; i++) {
    temp = c1;
    MyVector.push_back(temp);
}
Run Code Online (Sandbox Code Playgroud)

你们是对的,我明白我在这里做错了什么。实际的对象在每个循环中都会被破坏。在保持当前结构的同时解决这个问题的最佳方法是什么?我很难解释,但我想保留这个结构(将临时缓冲区保留在循环之外)..这可能吗?

Ric*_*dle 5

我将竭尽全力,用我的心灵力量来推导真正的代码,而不是问题中的简化代码。你的真实代码看起来像...鼓声...

class MyClass {
    // ...
};

void addInstance(std::vector<MyClass*>& MyVector, int i) {
    MyClass c("", i);
    MyVector.push_back(&c);
}

int main() {
    addInstance(MyVector, 1);
    addInstance(MyVector, 2);
    // ...
 }
Run Code Online (Sandbox Code Playgroud)

这是一个演示该问题的工作示例,它确实输出“2, 2”(尽管不能保证这一点,因为您正在调用未定义的行为):

http://ideone.com/PxiUx9

编辑:我的心灵力量说“函数中的自动变量”(现在我们有了更新的问题)它实际上是“循环中的自动变量”。还不错。:-)

您存储的自动变量的地址超出了其生命周期,这是不允许的。该地址在每次调用时都会重复使用,因此存储的每个指针都是相同的,并且恰好指向最后用于存储最近创建的 MyClass 实例的内存(尽管不能保证)。

您需要(最好)存储这些自动变量的副本而不是指向它们的指针,或者(不太优选)使用 来创建它们new,然后使用 来删除它们delete

要存储副本,您需要使用std::vector<MyClass>. 以下是如何做到这一点的示例:http://ideone.com/4rIijM 请注意,一旦您的类变得更加复杂,您可能需要定义复制构造函数、析构函数和赋值运算符 - 查找“三法则”。如果您使用的是 C++11,还要查找“五规则”。