C++:为什么在这里调用析构函数?

Nic*_*ner 1 c++ destructor

我想我不完全理解析构函数在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);
}
Run Code Online (Sandbox Code Playgroud)

main()结束之前,该程序的输出是:

Destructing Odp 0
Destructing Odp 1
Run Code Online (Sandbox Code Playgroud)

为什么会这样?我保留了对Odp向量中每个实例的引用.是否与传递shared_ptr引用有关?

更新我认为shared_ptr::reset根据MSDN递减引用计数:

运算符都减少当前由*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;
}
Run Code Online (Sandbox Code Playgroud)

ric*_*dwb 12

这条线路可能正在绊倒你.

shpoutOdp.reset(iter->get());
Run Code Online (Sandbox Code Playgroud)

你在这里做的是get()从智能指针获取(通过)裸指针,它不会有任何参考跟踪信息,然后告诉shpoutOdp重置自己指向裸指针.当shpoutOdp被破坏时,它不知道还有另一个shared_ptr指向同一个东西,并shpoutOdp继续破坏它所指向的东西.

你应该这样做

shpoutOdp = *iter;
Run Code Online (Sandbox Code Playgroud)

这将正确保持引用计数.顺便说一句,reset()确实递减参考计数器(并且只有在计数达到0时才会销毁).