C++ 为什么每个函数的STL算法调用我的函子的析构函数两次?

C++ 为什么每个函数的STL算法调用我的函子的析构函数两次?,c++,foreach,destructor,functor,stl-algorithm,C++,Foreach,Destructor,Functor,Stl Algorithm,我在试验STL算法,更具体地说是for_的每个函数。 我尝试了一个连接字符串向量的简单用例。请注意,这可能不是一个好的和/或高效的代码。如果您真的想连接字符串向量,请查看boost::algorithm::join函数 #include <iostream> #include <string> #include <vector> #include <algorithm> #include "concatenator.h" using namesp

我在试验STL算法,更具体地说是for_的每个函数。 我尝试了一个连接字符串向量的简单用例。请注意,这可能不是一个好的和/或高效的代码。如果您真的想连接字符串向量,请查看boost::algorithm::join函数

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "concatenator.h"

using namespace std;

int main(int argc, char **argv) {
     vector<string> list;
     list.push_back("hello");
     list.push_back("world");
     list.push_back("!!!");
     Concatenator concatenator;
     for_each(list.begin(), list.end(), concatenator);
     cout << "result = " << concatenator.getResult() << endl;
}
#包括
#包括
#包括
#包括
#包括“concatenator.h”
使用名称空间std;
int main(int argc,字符**argv){
向量表;
列表。推回(“你好”);
列表。推回(“世界”);
列表。向后推(!!!);
连接器连接器;
对于每个(list.begin()、list.end()、concatenator);

cout当您实现析构函数时,很可能还需要实现复制构造函数和复制赋值运算符。这称为


一旦您正确地实现了这两种方法,那么您将看到它并没有调用析构函数两次,而是创建一个副本并销毁每个副本。

当您实现析构函数时,很可能还需要实现一个副本构造函数和副本赋值操作符。这就是所谓的


一旦你正确地实现了这两个方法,你就会发现它并没有调用析构函数两次,而是复制并销毁了每个副本。

std::for_each
通过值而不是引用获取函子对象。然后它通过值返回它。换句话说,你的原始函子对象永远不会得到s已修改。因此您需要执行以下操作:

concatenator = for_each(list.begin(), list.end(), concatenator);

顺便说一句,传递值必然创建对象的副本,因此额外的析构函数调用。

std::for\u每个
都按值而不是引用获取函子对象。然后它按值返回。换句话说,您的原始函子对象永远不会被修改。因此您需要执行以下操作:

concatenator = for_each(list.begin(), list.end(), concatenator);

顺便说一句,pass by value必然创建对象的副本,因此额外的析构函数调用。

函数对象按值传递给
for_each
,并按值返回
for_each
,因此创建了
串联器的三个实例:

  • 您可以使用
    Concatenator Concatenator;
  • 您将此对象传递给
    for_each
    并复制它,因为
    for_each
    按值获取它
  • for_each
    按值返回functor,从而创建另一个副本

  • 这三个对象中的每一个都被销毁,因此析构函数被调用三次。

    函数对象按值传递给
    for_Each
    ,并按值返回
    for_Each
    ,因此创建了三个
    串联器的实例:

  • 您可以使用
    Concatenator Concatenator;
  • 您将此对象传递给
    for_each
    并复制它,因为
    for_each
    按值获取它
  • for_each
    按值返回functor,从而创建另一个副本

  • 这三个对象中的每一个都被销毁,因此析构函数被调用三次。

    for\u Each
    按值获取函子并返回其副本作为返回值,因此修改的不是你的
    串联函数,而是每个
    函数的本地函数。你应该更改您的代码应该是这样的:

     Concatenator concatenator;
     concatenator = for_each(list.begin(), list.end(), concatenator);
    
    concatenator
    中,现在您将拥有修改后的函子


    关于析构函数调用:它们在
    for_each
    返回时开始;第一个是
    for_each
    的参数之一,第二个是
    for_each
    返回的副本之一(被丢弃),第三个是原始的
    串联器
    对象的一个,当程序结束时,该对象将被销毁。

    for_each
    按值获取函子并返回其副本作为返回值,因此修改的不是你的
    串联器
    ,而是
    for_each
    函数的本地对象n返回。您应该将代码更改为:

     Concatenator concatenator;
     concatenator = for_each(list.begin(), list.end(), concatenator);
    
    concatenator
    中,现在您将拥有修改后的函子


    关于析构函数调用:它们在
    for_each
    返回时开始;第一个是
    for_each
    的参数之一,第二个是
    for_each
    返回的副本之一(被丢弃),第三个是原始的
    串联器
    对象中的一个,当程序结束时,该对象将被销毁。

    其他答案已经向您解释过,在您的情况下,问题是函子对象被传递给每个
    ,并通过值从每个
    返回

    <>但是,虽然< <每个> <代码>的声明对这个行为负责,但最后一个词是由C++的模板参数推导机制所说的。
    for_each(list.begin(), list.end(), concatenator);
    
    每个
    模板的
    的第二个参数被推断为
    串联器
    ,而不是
    串联器&
    ,从而产生传递值语义

    您可以通过显式指定模板参数、坚持第二个模板参数的引用类型来重写推断

    for_each<vector<string>::iterator, Concatenator &>(ist.begin(), list.end(),
        concatenator);
    
    对于每个(ist.begin()、list.end(),
    串联器);
    

    这将完全消除复制,并用传递引用语义替换传递值语义(还包括每个
    返回值)。它看起来不那么优雅,特别是因为函子类型恰好是第二个模板参数,但它是一个解决方法。

    其他答案已经向您解释过,在您的案例中,问题是函子对象被传递给
    for each
    ,并通过值从
    for each
    返回

    然而,尽管声明