【问题标题】:Why the destructors are called twice for this functor?为什么这个函子的析构函数被调用了两次?
【发布时间】:2013-04-14 13:38:07
【问题描述】:

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

#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

【问题讨论】:

  • 谢谢大家。感谢您的投入。

标签: c++ stl foreach


【解决方案1】:

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

#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、
构造函数(副本)
析构函数
析构函数

【讨论】:

  • 所以这证明副本在你的情况下被省略了。
  • 感谢您的解释。但是为什么复制构造函数发生在所有元素都被访问之后而不是之前呢?
  • @user373215:for_each 函数返回您传递给它的函数对象的副本。您的类不可移动(或者这不是 C++11),因此必须制作一个副本。
  • 谢谢大卫。欣赏它。
【解决方案2】:

原因是std::for_each 采用其参数按值,这会导致生成您提供的参数的副本

因此,您通过 sample() 创建的临时对象的销毁将负责这两条销毁消息之一(最后一条,因为在评估创建它的完整表达式后销毁临时文件)。

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

【讨论】:

  • 为什么移动对象会多调用1次析构函数? (即..., iNumbers.end() , std::move(sample()) )
  • @0x499602D2:可能是因为它可以防止复制省略。 std::for_each 可能在内部负责其中的 2 条消息,而由于复制省略,第一个不存在(临时在函数参数中直接构造)。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2013-01-12
      • 2011-01-02
      • 2021-11-06
      • 1970-01-01
      • 2013-11-24
      • 2015-07-26
      • 2020-02-23
      • 2013-12-11
      相关资源
      最近更新 更多