以下虚拟程序模仿了我正在解决的另一个程序的行为。

#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;
    }
}

我编译并运行为:
$ 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
$

由于某种原因,Ab vector 中objs对象的状态在b.DoTheThing()调用和后续打印语句之间改变。我的问题是发生了什么A对象data vector 是否超出范围并被删除,或者整个A对象?这似乎是一个范围界定的问题-甚至可能是一个简单的问题-但自从我用C++编程以来就已经不确定了很长时间。在其他方法中调用data之后,如何使b.DoTheThing() vector 的内容持久化?

最佳答案


void DoTheThing()
{
  for(auto obj : objs)
   // ^^^^^^^ receive by value due to implicit copy

实际上,您是将objs单独复制到单个临时obj中。 B::DoThething()完成后,这些临时对象将被销毁。为了避免复制,请使用引用:
  for(auto& obj : objs)
   // ^^^^^^^ receive by reference
main()中的类似循环也是如此。

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

如果可以承受,则将复制构造函数设置为explicit,以避免隐式复制:
class A {
public:
  A () = default;
  explicit A(const A&) = default;  // implicit copy is avoided
  A (A&&) = default;  // to avoid RVO related issues
  ...
};

这是demo,它显示explicit如何生成编译错误以解决for循环中意外生成副本的问题。
explicit带来了自己的语法限制。其中有些可以解决,有些则不能。请参阅以下问题中的1个此类问题(及其解决方法):

What is the effect of 'explicit' keyword on the Return Value Optimization (RVO)?

关于c++ - 为什么方法作用域完成后 vector 内容会发生变化?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38968068/

10-12 17:54
查看更多