我想我并不完全理解析构函数在 C++ 中的工作原理。这是我为重现问题而编写的示例程序:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
struct Odp
{
int id;
Odp(int id)
{
this->id = id;
}
~Odp()
{
cout << "Destructing Odp " << id << endl;
}
};
typedef vector<shared_ptr<Odp>> OdpVec;
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
shpoutOdp.reset();
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp.reset(iter->get());
return true;
}
}
return false;
}
int main()
{
OdpVec vec;
vec.push_back(shared_ptr<Odp>(new Odp(0)));
vec.push_back(shared_ptr<Odp>(new Odp(1)));
vec.push_back(shared_ptr<Odp>(new Odp(2)));
shared_ptr<Odp> shOdp;
bool found = findOdpWithID(0, shOdp, vec);
found = findOdpWithID(1, shOdp, vec);
}
就在 main()
结束之前,这个程序的输出是:
Destructing Odp 0
Destructing Odp 1
为什么会这样?我保留了对 vector 中每个 Odp
实例的引用。它与通过引用传递 shared_ptr
有什么关系吗?
更新 我认为 shared_ptr::reset
减少了引用计数,基于 MSDN :
The operators all decrement the reference count for the resource currently owned by *this
但也许我误会了?
更新 2:看起来这个版本的 findOdpWithID()
不会导致调用析构函数:
bool findOdpWithID(int id, shared_ptr<Odp> shpoutOdp, OdpVec& vec)
{
for (OdpVec::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
Odp& odp = *(iter->get());
if (odp.id == id)
{
shpoutOdp = *iter;
return true;
}
}
return false;
}
最佳答案
这里的这条线可能会让您感到困惑。
shpoutOdp.reset(iter->get());
你在这里做的是(通过 get()
)从智能指针获取裸指针,它上面没有任何引用跟踪信息,然后告诉 shpoutOdp
将自身重置为指向裸指针。当 shpoutOdp
被破坏时,它不知道还有另一个 shared_ptr
指向相同的东西,并且 shpoutOdp
继续破坏它所指向的东西到。
你应该这样做
shpoutOdp = *iter;
这将正确维护引用计数。顺便说一句,reset()
确实会减少引用计数器(并且仅在计数为 0 时才销毁)。
关于C++:为什么要在这里调用析构函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3214837/