C++ 为什么每个函数的STL算法调用我的函子的析构函数两次?
我在试验STL算法,更具体地说是for_的每个函数。 我尝试了一个连接字符串向量的简单用例。请注意,这可能不是一个好的和/或高效的代码。如果您真的想连接字符串向量,请查看boost::algorithm::join函数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
#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
返回
然而,尽管声明