c – 带有类参数的std :: thread初始化结果,类对象被多次复制
发布时间:2020-12-16 07:14:46 所属栏目:百科 来源:网络整理
导读:似乎如果你创建一个类的对象,并将它传递给std :: thread初始化构造函数,那么类对象的构造和销毁总体上是4次.我的问题是:你能一步一步地解释这个程序的输出吗?为什么这个类在这个过程中被构造,复制和破坏很多次? 示例程序: #include iostream #include cs
似乎如果你创建一个类的对象,并将它传递给std :: thread初始化构造函数,那么类对象的构造和销毁总体上是4次.我的问题是:你能一步一步地解释这个程序的输出吗?为什么这个类在这个过程中被构造,复制和破坏很多次?
示例程序: #include <iostream> #include <cstdlib> #include <ctime> #include <thread> class sampleClass { public: int x = rand() % 100; sampleClass() {std::cout << "constructor called,x=" << x << std::endl;} sampleClass(const sampleClass &SC) {std::cout << "copy constructor called,x=" << x << std::endl;} ~sampleClass() {std::cout << "destructor called,x=" << x << std::endl;} void add_to_x() {x += rand() % 3;} }; void sampleThread(sampleClass SC) { for (int i = 0; i < 1e8; ++i) { //give the thread something to do SC.add_to_x(); } std::cout << "thread finished,x=" << SC.x << std::endl; } int main(int argc,char *argv[]) { srand (time(NULL)); sampleClass SC; std::thread t1 (sampleThread,SC); std::cout << "thread spawned" << std::endl; t1.join(); std::cout << "thread joined" << std::endl; return 0; } 输出是: constructor called,x=92 copy constructor called,x=36 copy constructor called,x=61 destructor called,x=36 thread spawned copy constructor called,x=62 thread finished,x=100009889 destructor called,x=61 thread joined destructor called,x=92 用gcc 4.9.2编译,没有优化. 解决方法
在后台有很多复制/移动.但请注意,在调用线程构造函数时,既不调用复制构造函数也不调用移动构造函数.
考虑这样的函数: template<typename T> void foo(T&& arg); 当你对模板参数进行r值引用时,C对此有点特殊.我将在这里概述规则.当您使用参数调用foo时,参数类型将为 >&& – 当参数是r值时 也就是说,参数将作为r值引用或标准引用传递.无论哪种方式,都不会调用构造函数. 现在看一下线程对象的构造函数: template <class Fn,class... Args> explicit thread (Fn&& fn,Args&&... args); 此构造函数应用相同的语法,因此永远不会将参数复制/移动到构造函数参数中. 以下代码包含一个示例. #include <iostream> #include <thread> class Foo{ public: int id; Foo() { id = 1; std::cout << "Default constructor,id = " << id << std::endl; } Foo(const Foo& f) { id = f.id + 1; std::cout << "Copy constructor,id = " << id << std::endl; } Foo(Foo&& f) { id = f.id; std::cout << "Move constructor,id = " << id << std::endl; } }; void doNothing(Foo f) { std::cout << "doNothingn"; } template<typename T> void test(T&& arg) { } int main() { Foo f; // Default constructor is called test(f); // Note here that we see no prints from copy/move constructors std::cout << "About to create thread objectn"; std::thread t{doNothing,f}; t.join(); return 0; } 这段代码的输出是 Default constructor,iCount = 1 About to create thread object Copy constructor,id = 2 Move constructor,id = 2 doNothing >首先,创建对象.>我们调用我们的测试函数只是为了看到没有任何反应,没有构造函数调用.>因为我们将l值传递给线程构造函数,所以参数具有类型l-value引用,因此将对象(使用复制构造函数)复制到线程对象中.>将对象移动到底层线程(由线程对象管理)>最终将对象移入线程函数doNothing的参数中 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |