传递临时对象要注意的陷阱


传递临时对象要注意的陷阱

  1. 引用虽然编译器进行了值拷贝,但是不推荐用。
  2. 指针一定会出现临时对象的传递错误
void myfunc_detach(const int& i, const char* ptr)
{
    cout << i << endl;      //调式是myvar 和 i 是两个不同的地址,即编译器进行了值拷贝操作 
    cout << ptr << endl;    //str 和 ptr 是同一个地址,假如detach后主线程先结束,临时对象str会被销毁,ptr指向非法地址空间
}

int main()
{
    int i1 = 12;
    int& myvar = i1;
    char str[] = { "this is a string!" };

    thread  mythr(myfunc_detach, myvar, str);
    //mythr.join();
    mythr.detach(); //这里会出现非预期的值传递异常
    cout << "hi~" << endl;
}

关于指针传输出现得问题,可以暂时修改形参的方式更正这个隐藏的陷阱

void myfunc_detach(const int& i, const string& ptr)
{
    ...
}

但是这里存在的问题是:可能main线程已经结束了,str 才会去进行string 类型转换,这也是对非法内存空间的非法操作。

  • 真正正确的更正如下:
...
thread  mythr(myfunc_detach, myvar, string(str));
...

string(str) 会生成临时对象,而临时对象会绑定到const string& ptr 这个引用上。
临时对象传递给线程是可行的,此时即使.detach() 子线程也是可以安全运行的。

  • 类比说明
using namespace std;
class Atrmp
{
public:
    int var;

    Atrmp(int a);
    Atrmp(const Atrmp& cla);
    ~Atrmp();

private:

};

Atrmp::Atrmp(int a):var(a)
{
    cout << "Atrmp::Atrmp(int a)构造函数执行" << this << endl;
}
Atrmp::Atrmp(const Atrmp& cla):var(cla.var) {
    cout << "Atrmp::Atrmp(Atrmp& cla):var(cla.var)拷贝构造函数执行" << this << endl;
}

Atrmp::~Atrmp()
{
    cout << "Atrmp::~Atrmp()析构函数执行" << this << endl;
}
void func(int a, const Atrmp& rmp)
{
    cout << &rmp << endl;
}
int main()
{
    int x = 1;
    int trmp = 12;
    //thread my1(func, x, trmp);
    thread my1(func, x, Atrmp(trmp));
    //my1.join();
    my1.detach();

    return 0;
}

thread my1(func, x, trmp);
my1.join();
  • join()运行的结果
    在这里插入图片描述

thread my1(func, x, Atrmp(trmp));
my1.detach();
  • detach()时运行的结果
    在这里插入图片描述

detach 时注意事项

  1. 若传递 int 这种简单的类型参数,建议使用值传递,不要用引用。
  2. 如果传递类对象,避免隐式类型转换,全部在创建线程那一行构建出临时对象出来,在线程函数那里用引用来接,否则系统会额外构建一个对象出来。


线程ID的获取

std::this_thread::get_id()

传递类对象,智能指针作为线程参数

std::ref 在传递对象的时候,实参加上该修饰,就可以在子线程中修改值了。此时的参数直接传递,并没有进行拷贝

智能指针的传递示意如下:

void func2(unique_ptr <int> p) {

}

int main(){
    unique_ptr<int> mp(new int(10));
    thread my2(func2, std::move(mp));
    my2.join();
    return 0;
}

用成员函数指针作线程参数

using namespace std;
class Atrmp
{
public:
    int var;

    Atrmp(int a);
    Atrmp(const Atrmp& cla);
    ~Atrmp();

    void classfunc(int num);

private:

};

Atrmp::Atrmp(int a):var(a)
{
    cout << "Atrmp::Atrmp(int a)构造函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}
Atrmp::Atrmp(const Atrmp& cla):var(cla.var) {
    cout << "Atrmp::Atrmp(Atrmp& cla):var(cla.var)拷贝构造函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}

Atrmp::~Atrmp()
{
    cout << "Atrmp::~Atrmp()析构函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}
void Atrmp::classfunc(int num)
{
    cout << "classfunc执行了" << this << "Thread_ID:" << this_thread::get_id() << endl;
}

int main()
{
    Atrmp myobj(10);
    thread myth(&Atrmp::classfunc, myobj, 12);
    //thread myth(&Atrmp::classfunc, ref(myobj), 12);
    myth.join();
    
    return 0;
}

可调用类对象最为线程指针

using namespace std;
class mycla1
{
public:
    mycla1(int a);
    mycla1(const mycla1& c);
    ~mycla1();
    void operator()(int x);
    
    int m_i;
private:

};

mycla1::mycla1(int a):m_i(a)
{
    cout << "mycla1::mycla1(int a)构造函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}

mycla1::mycla1(const mycla1& c) : m_i(c.m_i)
{
    cout << "mycla1::mycla1(const mycla1& c)拷贝构造函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}

mycla1::~mycla1()
{
    cout << "mycla1::~mycla1()析构函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
}
void mycla1::operator()(int x)
{
    cout << "mycla1 mycla1::operator()(int x)函数执行" << this << "Thread_ID:" << this_thread::get_id() << endl;
    //return *this;
}

int main()
{
    mycla1 myobjective(7);
    thread mytive(myobjective, 12);
    mytive.join();
    
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值