以下虚拟程序模仿了我正在解决的另一个程序的行为。
#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
$
由于某种原因,
A
的b
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/