以下虚拟程序模仿我正在排除故障的另一个程序的行为。
#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
$
由于某些原因,b
的 objs
vector 中的 A
对象的状态在 b.DoTheThing( )
调用和后续的打印语句。我的问题是发生了什么? A
对象 data
vector 是否超出范围并被删除,或者可能是整个 A
对象?这似乎是一个范围界定问题——甚至可能是一个微不足道的简单问题——但自从我用 C++ 编程以来它已经足够长了,我不确定。在其他方法中调用 b.DoTheThing()
后,如何使 data
vector 的内容保持不变?
最佳答案
"For some reason the state of the
A
objects in b'sobjs
vector
is changing between theb.DoTheThing()
call and the subsequent print statements. My question is what is happening?"
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()
中的类似循环也是如此。
真正的问题可以是:“如何避免此类事故?”
如果你负担得起,那么将复制构造函数设为显式
以避免隐式复制:
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/