为什么在方法范围结束后矢量内容发生了变化?

Dan*_*age 2 c++ scope for-loop vector

以下虚拟程序模仿我正在排除故障的另一个程序的行为.

#include <iostream>
#include <vector>

class A
{
public:
    std::vector<int> data;

    void DoTheThing()
    {
        while (data.size() < 10) {
            data.push_back(1);
        }
    }
};

class B
{
public:
    std::vector<A> objs;

    B()
    {
        A one, two, three;
        objs.push_back(one);
        objs.push_back(two);
        objs.push_back(three);
    }

    void DoTheThing()
    {
        for (auto obj: objs) {
            obj.DoTheThing();
            std::cout << "DEBUG length during=" << obj.data.size() << std::endl;
        }
    }
};

int main()
{
    B b;
    b.DoTheThing();
    for (auto obj : b.objs) {
        std::cout << "DEBUG length  after=" << obj.data.size() << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

我编译并运行为:

$ g++ -Wall --std=c++11 -o test test.cpp
$ ./test
DEBUG length during=10
DEBUG length during=10
DEBUG length during=10
DEBUG length  after=0
DEBUG length  after=0
DEBUG length  after=0
$
Run Code Online (Sandbox Code Playgroud)

出于某种原因,状态A物体bobjs向量之间改变b.DoTheThing()呼叫和后面的print语句.我的问题是发生了什么A对象data向量是否以某种方式超出范围并被删除,或者可能是整个A对象?这似乎是一个范围问题 - 可能甚至是一个简单的问题 - 但它已经足够长了,因为我用C++编程我不确定.data在调用b.DoTheThing()其他方法后,如何使向量的内容保持不变?

iam*_*ind 6

"出于某种原因A,b中对象的状态objs vectorb.DoTheThing()调用和后续的打印语句之间发生了变化.我的问题是发生了什么? "

void DoTheThing()
{
  for(auto obj : objs)
   // ^^^^^^^ receive by value due to implicit copy
Run Code Online (Sandbox Code Playgroud)

您实际上正在单独复制objs到单个临时objs中.那些临时工作在B::DoThething()完成后被摧毁.要避免副本,请使用参考:

  for(auto& obj : objs)
   // ^^^^^^^ receive by reference
Run Code Online (Sandbox Code Playgroud)

对于类似的循环也是如此main().


真正的问题可能是:"如何避免此类事故?"

如果你能负担得起,那么制作复制构造函数explicit以避免隐式复制:

class A {
public:
  A () = default;      
  explicit A(const A&) = default;  // implicit copy is avoided
  A (A&&) = default;  // to avoid RVO related issues
  ...
};
Run Code Online (Sandbox Code Playgroud)

这是一个演示,它演示了如何explicit生成编译错误以捕获for循环中的问题,这意外地进行了复制.


explicit带来它自己的语法限制.其中一些可以解决,一些不能解决.请参阅以下问题以解决1个问题(及其解决方法):

'explicit'关键字对返回值优化(RVO)的影响是什么?