为什么函子的 dtor 在作为函数的参数传递给线程时调用两次(多次)
Why dtors of functors called twice (multitimes), when passed to a thread as the argument for Function?
由于以下示例,我有这个问题:
#include <utility>
#include <thread>
#include <iostream>
typedef struct foo{
foo() = default;
void operator()(int i) const {}
~foo(){std::cout<<"dtorn";}
} foo;
typedef struct bar{
bar() = default;
bar(const bar&) {std::cout<<"copyn";}
bar(bar&&) {std::cout<<"moven";}
void operator()(const foo& f, int k) const {f(k);}
~bar(){std::cout<<"barn";}
} bar;
int main(){
foo f_1, f_2;
bar b_1, b_2;
int i(0), j(0);
while(i++!=2){
std::thread t(b_1, std::cref(f_1), i);
b_2(f_2, j);
t.join();
}
int dummy(0);
std::cin >> dummy;
}
哪个产量(GCC 和 clang 给出相同的结果)
copy
move
bar
bar
copy
move
bar
bar
0
bar
bar
dtor
dtor
,其中 0 是用户输入。
因此,柱形的 dtor(函数的参数)在胎面完成其工作(每次迭代)后被调用两次。我不明白的是,为什么两次而不是一次(用于制作副本)?
此外,如果函子本身持有不可复制的资源或复制成本很高,是否可以避免复制?
谢谢!
更新它不一定是原始问题的两倍,请参阅下面的 Praetorian 的答案,其中涉及 3 个 dtor 调用和 2 个动作。
你正在将一个左值(b_1
)传递给std::thread
构造函数,所以它会复制该参数。我已经修改了您的示例,以便更容易了解正在发生的事情。请注意,while
条件已更改,因此它只执行一次。
typedef struct foo{
foo() = default;
void operator()(int i) const {}
// ~foo(){std::cout<<"dtorn";}
} foo;
typedef struct bar{
bar() {std::cout<<"bar " << this << 'n';}
bar(const bar&) {std::cout<<"bar copy " << this << 'n';}
bar(bar&&) {std::cout<<"bar move " << this << 'n';}
void operator()(const foo& f, int k) const {f(k);}
~bar() {std::cout<<"~bar " << this << 'n';}
} bar;
int main(){
foo f_1, f_2;
bar b_1, b_2;
int i(0), j(0);
while(i++!=1){
std::cout << "---- 1 ----n";
std::thread t(b_1, std::cref(f_1), i);
std::cout << "---- 2 ----n";
b_2(f_2, j);
t.join();
std::cout << "---- 3 ----n";
}
}
在 gcc 上,这会产生输出(注释是我的)
bar 0x7fffbcc2156c // b_1 constructed
bar 0x7fffbcc2156d // b_2 constructed
---- 1 ----
bar copy 0x7fffbcc21580 // std::thread ctor makes copy of b_1
bar move 0x162a038 // that copy is moved by std::thread impl
~bar 0x7fffbcc21580 // moved from object is destructed
---- 2 ----
~bar 0x162a038 // bar object owned by thread instance is destroyed
---- 3 ----
~bar 0x7fffbcc2156d // b_2 is destroyed
~bar 0x7fffbcc2156c // b_1 is destroyed
clang 的输出是相同的。
如果您想避免该副本,有几个不同的选项。您可以将b_1
实例包装在 std::reference_wrapper
中,然后再将其传递给 std::thread
。
std::thread t(std::cref(b_1), std::cref(f_1), i);
现场演示
或者,您可以允许std::thread
构造函数移动b_1
实例。
std::thread t(std::move(b_1), std::cref(f_1), i);
现场演示。在这种情况下,您将产生std::thread
实现执行的内部移动构造。
相关文章:
- 在c++中多次调用方法
- 如何使用运算符在同一行中多次调用函数
- 在C++中多次调用相同的 lambda
- 函数被多次调用
- std::async 如何工作:为什么它会调用这么多次复制/移动?
- 多次调用本机方法时出现致命错误
- Singleton模式中的手动析构函数调用:调用多次
- 系统调用:一次和多次,哪个更好?
- 为什么在杂注 omp 关键之后多次调用 printf 会产生乱码输出?
- 如何转换多次调用自己的递归算法?
- free():多次调用后下一个大小(快速)无效
- 如何使用不同的参数多次调用函数
- 从不同的节点插件方法多次调用JS函数
- Cython c++模块,多次调用构造函数
- 为循环中多次调用的函数返回值预分配内存的正确方法是什么
- 多次调用存储过程时C++连接器"Commands out of sync" mySQL
- C++错误,隐 <function-style-cast> 式要求使用模板化类一次调用多个构造函数的多个转换
- 为什么我的析构函数被调用多次
- 块范围静态的析构函数可以调用多次
- 在对象数组中,构造函数被调用多次,但运算符new[]只被调用一次,原因是什么