C++函数参数临时对象销毁时机及代码崩溃问题咨询
C++临时对象生命周期与代码崩溃问题解答
简短版问题
如下代码中:
QString dataStr; myfunc(dataStr.toUtf8().constData());
toUtf8()创建的临时QByteArray对象是在进入myfunc()作用域前销毁,还是会被保证在myfunc()调用结束后才销毁?
详细版背景
我正在维护一段类似如下的代码:
class Request { public : std::function<void()> requestFunc; }; void myfunc(const char* data) { auto request = new Request(); auto lambda = [](const std::string& str) { cout << str; }; // 使用data request->requestFunc = std::bind(std::move(lambda), std::string(data)); requestQueue.push(std::move(request)); } QString dataStr; myfunc(dataStr.toUtf8().constData()); // 一段时间后,requestQueue被处理,requestFunc被调用
一位同事的机器上出现了崩溃问题。我们通过显式修改toUtf8()创建的临时QByteArray对象的作用域解决了该问题:
... QString dataStr; const QByteArray tempObj = dataStr.toUtf8(); myfunc(tempObj.constData());
问题得到解决,但之后我们与另一位同事讨论时,我并不清楚C++标准/编译器是否会保证临时对象存活至函数调用结束,还是其作用域仅限于参数,导致进入myfunc()后临时对象已被销毁。
我总结了两种能解释该“修复”的可能性:
- 临时对象确实在进入函数前就已销毁,此时
constData()指向已释放的内存。由于使用前没有过多操作,内存通常仍保留正确值且未被覆盖,这就是为什么多数情况下代码能正常运行,而修改后的版本是正确的修复方案。 - 临时对象仅在函数调用结束后才销毁。这意味着bug出在其他地方,该“修复”只是延迟了临时对象的销毁,从而降低了已释放内存被覆盖的概率。
如果是后一种情况,您知道bug可能出在哪里吗?
编辑补充:
后来发现问题出在我之前的代码上。修改前我是这样写的:
QString dataStr; const char* dataPtr = dataStr.toUtf8().constData(); myfunc(dataPtr);
因此临时对象在调用myfunc()前就已被销毁。
核心解答
临时对象生命周期的C++标准规定
- 作为函数实参的临时对象:当临时对象直接作为函数调用的实参时,它的生命周期会被延长至整个函数调用表达式完成,也就是
myfunc()执行完毕之后才会销毁。所以在myfunc(dataStr.toUtf8().constData());这行代码中,toUtf8()创建的临时QByteArray会存活到myfunc()执行结束,此时myfunc()内部使用data指针是安全的。 - 赋值给指针后的临时对象:如果像你补充的错误写法那样,把临时对象的
constData()赋值给指针后再调用函数:
这里const char* dataPtr = dataStr.toUtf8().constData(); myfunc(dataPtr);toUtf8()返回的临时QByteArray在赋值语句结束时就会立即销毁(临时对象的生命周期仅覆盖它所在的完整表达式),导致dataPtr指向已释放的内存。后续调用myfunc()时使用该指针属于未定义行为,这就是崩溃的直接原因。
对两种可能性的分析
- 你的第一种假设完全符合实际场景:错误写法中临时对象确实在
myfunc()调用前就销毁了,显式保存QByteArray的修改方案是正确的——因为tempObj的生命周期会覆盖myfunc()的整个调用过程,甚至更长,确保constData()指向的内存始终有效。 - 第二种假设的场景不成立:如果是直接用
myfunc(dataStr.toUtf8().constData());的写法,临时对象会存活到函数调用结束,myfunc()内部用std::string(data)构造字符串时会复制内存内容,后续requestFunc调用的是绑定的std::string副本,和原临时对象无关,不会出现崩溃。
内容的提问来源于stack exchange,提问作者Mickaël C. Guimarães
相关产品推荐
相关产品推荐

