for 循环中的共享指针向量 getter 导致问题
Shared pointer vector getter in for loop causing problems
我一直在试验向量和共享指针,我遇到了以下情况。我无法解释正在发生的事情。代码是
#include<iostream>
#include<vector>
#include<memory>
class A
{
public:
int val;
A(int val1): val(val1){}
};
class B
{
std::vector< std::shared_ptr<A> > path;
public:
std::vector< std::shared_ptr<A> > getPath() { return path; }
void doIt()
{
std::shared_ptr<A> a1 = std::make_shared<A>(1);
std::shared_ptr<A> a2 = std::make_shared<A>(2);
std::shared_ptr<A> a3 = std::make_shared<A>(3);
path.push_back(a1);
path.push_back(a2);
path.push_back(a3);
std::cout<<"In function"<<std::endl;
for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
endItr = path.end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
}
};
int main()
{
B b;
b.doIt();
std::cout<<"In main"<<std::endl;
for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
endItr = b.getPath().end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
}
我得到的输出是
In function
0x30dc8: 1
0x31780: 2
0x317a0: 3
In main
0x35f18: 196800
0x31780: 2
0x317a0: 3
矢量的第一个元素由于某种原因指向另一个内存位置。
用下面的代码替换for循环就解决了问题,
std::vector< std::shared_ptr<A> > path = b.getPath();
for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
endItr = path.end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
有人可以向我解释一下第一种情况出了什么问题吗?我还想知道为什么在第二种情况下问题得到解决?
问题在这里:
for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
endItr = b.getPath().end(); itr != endItr; ++itr)
getPath()
returns 临时向量。您调用了两次,因此您得到 两个不同的 vector
。 itr
指向一个临时向量的 begin()
而 endItr
指向另一个临时向量的末尾。甚至在进入 for 循环之前,两个临时向量都超出了范围,因此一旦取消引用,您正在访问已经删除的内存。
这样做:
std::vector< std::shared_ptr<A> > path = b.getPath();
解决了这个问题,因为现在你的两个迭代器都指向 相同的 向量,这也会比两个迭代器都长。
另外,C++11。如果你只是使用基于范围的 for 表达式,你就不会有这个问题:
for (auto& a : b.getPath())
{
std::cout << &*a << ": " << a->val << std::endl;
}
这样更容易阅读。
我一直在试验向量和共享指针,我遇到了以下情况。我无法解释正在发生的事情。代码是
#include<iostream>
#include<vector>
#include<memory>
class A
{
public:
int val;
A(int val1): val(val1){}
};
class B
{
std::vector< std::shared_ptr<A> > path;
public:
std::vector< std::shared_ptr<A> > getPath() { return path; }
void doIt()
{
std::shared_ptr<A> a1 = std::make_shared<A>(1);
std::shared_ptr<A> a2 = std::make_shared<A>(2);
std::shared_ptr<A> a3 = std::make_shared<A>(3);
path.push_back(a1);
path.push_back(a2);
path.push_back(a3);
std::cout<<"In function"<<std::endl;
for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
endItr = path.end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
}
};
int main()
{
B b;
b.doIt();
std::cout<<"In main"<<std::endl;
for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
endItr = b.getPath().end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
}
我得到的输出是
In function
0x30dc8: 1
0x31780: 2
0x317a0: 3
In main
0x35f18: 196800
0x31780: 2
0x317a0: 3
矢量的第一个元素由于某种原因指向另一个内存位置。
用下面的代码替换for循环就解决了问题,
std::vector< std::shared_ptr<A> > path = b.getPath();
for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
endItr = path.end(); itr != endItr; ++itr)
{
std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}
有人可以向我解释一下第一种情况出了什么问题吗?我还想知道为什么在第二种情况下问题得到解决?
问题在这里:
for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
endItr = b.getPath().end(); itr != endItr; ++itr)
getPath()
returns 临时向量。您调用了两次,因此您得到 两个不同的 vector
。 itr
指向一个临时向量的 begin()
而 endItr
指向另一个临时向量的末尾。甚至在进入 for 循环之前,两个临时向量都超出了范围,因此一旦取消引用,您正在访问已经删除的内存。
这样做:
std::vector< std::shared_ptr<A> > path = b.getPath();
解决了这个问题,因为现在你的两个迭代器都指向 相同的 向量,这也会比两个迭代器都长。
另外,C++11。如果你只是使用基于范围的 for 表达式,你就不会有这个问题:
for (auto& a : b.getPath())
{
std::cout << &*a << ": " << a->val << std::endl;
}
这样更容易阅读。