为什么这个函子的析构函数被调用两次

Why the destructors are called twice for this functor?

本文关键字:调用 两次 析构函数 为什么      更新时间:2023-10-16

当我运行下面的程序时,析构函数被调用了两次,我试图理解为什么?

#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
    public:
        sample() { std::cout << "Constructor " << std::endl; }
        ~sample() { std::cout << "Destructor" << std::endl; }
        void operator()(int i)
        {
            std::cout << i << " , "  << std::endl;
        }
};
int main()
{
    std::vector<int> iNumbers;
    for ( int i = 0 ; i < 5 ; ++i)
        iNumbers.push_back(i);
    std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}

输出如下

Constructor
0 ,
1 ,
2 ,
3 ,
4 ,
Destructor
Destructor

经典的三违规则。试试这个:

#include <iostream>
#include <vector>
#include <algorithm>
class sample
{
    public:
        sample() { std::cout << "Constructor " << std::endl; }
        sample(const sample&) { std::cout << "Constructor (copy)" << std::endl; }
        ~sample() { std::cout << "Destructor" << std::endl; }
        sample& operator=(const sample&) { return *this; }
        void operator()(int i)
        {
                std::cout << i << " , "  << std::endl;
        }
};
int main()
{
    std::vector<int> iNumbers;
    for ( int i = 0 ; i < 5 ; ++i)
            iNumbers.push_back(i);
    std::for_each(iNumbers.begin() , iNumbers.end() , sample() );
}

输出是:


构造函数0,
1,
2,
3、
4、
构造函数(副本)
析构函数
析构函数

原因是std::for_each通过值获取其参数,这导致对您提供的参数进行复制

因此,通过执行sample()创建的临时的销毁将负责这两个销毁消息中的一个(最后一个,因为临时在创建它的完整表达式求值后被销毁)。

另一方面,第一个销毁消息来自std::for_each正在处理的副本的销毁。

std::for_each将按值获取函数对象,导致它被复制。因此,一个析构函数用于sample()创建的临时对象,另一个用于副本。

如果您编写了复制构造函数,您将看到函子被复制到算法中。然后销毁两个副本。函数子有可能被返回,并且有3个副本,因此其中一个副本被省略了。