std::for_each 和 std::vector 析构函数调用

Posted

技术标签:

【中文标题】std::for_each 和 std::vector 析构函数调用【英文标题】:std::for_each and std::vector destructor call 【发布时间】:2016-07-13 07:23:12 【问题描述】:

我对 std::for_each 和仿函数代理对象有以下问题。 见以下代码:

struct Functor 

  std::vector<int> data;

  const unsigned mID;
  static unsigned id;

  Functor() : mID(id++) 
     std::cout << "Functor constructed with id: " << mID << std::endl;
  

  ~Functor() 
    std::cout << "Functor dtor: " << mID << std::endl;
  

   void operator() (int i) 
      std::cout << "Functor print: " << i << std::endl;
      data.push_back(i);

      std::cout << "Dump: ";
      for(int i = 0; i < data.size(); ++i)
        std::cout << data[i] << " ";
      std::cout << std::endl;
   
;
unsigned Functor::id = 0;

从上面看,代理对象只做两件事,它将数据打印到 CMD 并存储一个副本供自己使用。下面是该对象的示例用例:

int main () 

  std::vector<int> intvec;
  for(int i = 0; i < 10; ++i)
    intvec.push_back(i);

  Functor myfunctor;
  std::for_each(intvec.begin(), intvec.end(), myfunctor);

  std::cout << "Data in my functor: " << myfunctor.data.size() << std::endl;
  for(int i = 0; i < myfunctor.data.size(); ++i)
    std::cout << "myfunctor data: " << myfunctor.data[i] << std::endl;

  return 0;

这对我来说真的很可疑。生成的输出是我的函子代理对象被构造了一次但被解构了三次!有东西绕过了构造调用。

同样由于在 std::for_each 结束时调用了析构函数,Functor.data 也是空的!

有没有办法确保 Functor 中的数据保持持久性?我希望在 std::for_each 等函数内部使用时跟踪我的仿函数的状态(基本上任何给定的 std 算法函数都可以接受一元仿函数)

请注意,我只使用 c++03。非常感谢。

【问题讨论】:

【参考方案1】:

[...] 我的仿函数代理对象构造了一次,但解构了 3 次!有东西绕过了构造调用。

不完全是。您的课程默认构造一次,但也复制构造两次。您不记录复制构造,因此它不会显示在您的输出中。

如果你添加一个日志复制构造函数,你会看到“FunctorConstructed with id: 0”打印了 3 次:

  Functor(const Functor& other) : mID(other.mID) 
     std::cout << "Functor constructed with id: " << mID << std::endl;
  

【讨论】:

好的,谢谢,这实际上解释了很多。有没有办法让我确保 std::for_each 在调用环境的范围内使用 Functor?类似于 c++11 的东西通过引用传递或通过指针传递。 @NPE

以上是关于std::for_each 和 std::vector 析构函数调用的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 std::for_each() 返回时调用转换运算符?

使用 std::for_each lambda 函数的错误

C++ STL应用与实现26: 如何使用std::for_each以及基于范围的for循环 (since C++11)

如何计算 std::for_each lambda 函数所需的类型

检查字符串是否相等

为啥 std::move 不能与 std::list 一起使用