在函数参数中创建的临时对象什么时候应该被销毁?

问题描述 投票:0回答:1

精简版

在此代码中:

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;
    }
    // Use data
    request->requestFunc = std::bind(std::move(lambda), std::string(data));
    requestQueue.push(std::move(request));
}

QString dataStr;

myfunc(dataStr.toUtf8().constData());

// Some time later, requestQueue gets managed and requestFunc gets called

我一位同事的一台机器崩溃了。我们解决了这个问题,显式更改了 toUtf8() 创建的临时 QByteArray 对象的范围:

...
QString dataStr;

const QByteArray tempObj = dataStr.toUtf8();
myfunc(tempObj.constData());

它解决了崩溃问题。但后来我们与另一位同事讨论,我不清楚 C++ 标准/编译器是否应该保留临时对象直到函数调用完成,或者它的范围是否仅限于参数,因此一旦进入 myfunc() 临时参数对象就已经被销毁了。

我看到的两种可能性解释了崩溃的“修复”:

  • 临时对象确实在进入函数之前被销毁,并且constData()指向已释放的内存。由于在使用之前没有发生太多事情,因此内存通常仍然保存着正确的值并且没有被覆盖。这就是为什么它在大多数情况下都有效,甚至是错误的,并且新版本是正确的修复
  • 临时对象只有在函数调用完成后才会被销毁。这意味着错误在其他地方,并且“修复”仅起作用,因为我们延迟了临时对象的销毁,从而降低了释放的内存被覆盖的可能性

如果是后一种情况,那么您知道错误可能出在哪里吗?

c++ memory-management standards
1个回答
1
投票

toUtf8() 创建的临时 QByteArray 对象是在进入 myfunc() 范围之前销毁还是保证在 myfunc() 调用完成后销毁?

该对象不是参数对象。它是一个临时对象。临时对象在创建它的完整表达式结束时被销毁,尽管存在一些例外情况,但都与本示例无关。请注意,参数对象,即对应于函数的非引用参数的对象,不是临时对象,并且遵循其他规则。

示例中完整表达式的结尾是在计算

myfunc(dataStr.toUtf8().constData())
之后,即在表达式语句的末尾。

© www.soinside.com 2019 - 2024. All rights reserved.