qPrintable的定义:
# define qPrintable(string) QString(string).toLocal8Bit().constData()
toLocal8Bit返回一个QByteArray。 QByteArray::constData()的文档:
只要字节数组未被重新分配或销毁,指针就会保持有效。
toLocal8Bit()创建一个临时的QByteArray,它在调用constData()之后被销毁。因此constData返回的指针指向释放的内存。
我在这里错过了什么吗?
补充意见: qPrintable的文档说明了这一点:
在使用qPrintable()的语句之后,char指针将无效。这是因为QString :: toLocal8Bit()返回的数组将超出范围。
但这是什么意思?根据我的理解,这与&#34相同;指针从qPrintable"
返回时起无效为什么我要问:
我看到代码失败,可以像这样简化:
someFunction( stringA.toLatin1().constData(), stringB.toLatin1().constData())
在被调用函数内部,两个参数都是指向同一地址的指针。
答案 0 :(得分:2)
qPrintable
宏应该用于调试目的:
qWarning("%s: %s", qPrintable(key), qPrintable(value));
或:
qDebug() << "My value is: " << qPrintable(value);
这里由QByteArray
创建的临时QString::toLocal8Bit
对象在整个语句结束后被销毁,这在使用QByteArray::constData()
指针后发生。
在这种情况下,我们遇到了您所描述的问题:
QString s = "Hello";
const char *debug_string = s.toLocal8Bit().constData();
// Can't use debug_string here as the pointer is invalid:
// qDebug() << debug_string
答案 1 :(得分:1)
根据我的理解,这与&#34相同;指针在qPrintable&#34;
返回时无效。
没有。临时对象在他们所参与的完整表达结束时被销毁,除非他们的生命因使用const引用而延长。有关详细信息,请参阅this question。只要完整表达式结束,指针就会无效。
在foo(obj1().method(), obj2().method())
之类的通话中,整个通话都是完整的表达。
所以,这将有效:
#include <QtCore>
struct Test {
Test() { qDebug() << "created"; }
~Test() { qDebug() << "destroyed"; }
Test * fun() { return this; }
};
void f1(Test *, Test*) { qDebug() << "f1"; }
int main()
{
f1(Test().fun(), Test().fun());
}
输出:
created
created
f1
destroyed
destroyed
我看到代码失败,可以这样简化:
someFunction( stringA.toLatin1().constData(), stringB.toLatin1().constData())
。在被调用函数内部,两个参数都是指向同一地址的指针。
&#34;简化&#34;好事。一旦将每个qPrintable
从完整的函数调用表达式中拉出来用作参数,事情就会失败:
int main()
{
auto a1 = Test().fun();
// here a1 dangles
auto a2 = Test().fun();
// here both a1 and a2 dangle
f1(a1, a2); // undefined behavior
}
输出:
created
destroyed
created
destroyed
f1
qPrintable是否容易发生访问冲突?
这取决于对C ++语义的了解程度。鉴于它是一个过时的和不必要的结构,我只是说:容易出现未定义的行为,没有理由使用它。如果您需要将QString
传递给期望const char *
的内容,请在适配器中明确说明。
void foo(const char *); // we need to call this with a QString
void foo2(const char *, const char *);
inline void foo(const QString & arg1) { // now we can
auto a1 { arg1.toLocal8Bit() };
foo(a1.constData()); // a1's lifetime explicitly extends past the call
}
// or if you really like one-liners
inline void foo2(const QString & arg1, const QString & arg2) {
foo2(arg1.toLocal8Bit().constData(), arg2.toLocal8Bit().constData());
}
答案 2 :(得分:0)
但这是什么意思?据我了解,这与“指针从qPrintable返回的那一刻起无效”相同。
我有相同的问题,但是理解这一点的关键是要注意到 qPrintable
是一个宏,而不是一个函数:
#ifndef qPrintable
# define qPrintable(string) QtPrivate::asString(string).toLocal8Bit().constData()
#endif
(来自here)。
如果它是一个函数,那将是对的。作为一个宏,没有回报可言。文档说“返回”,但这只是不精确的。因此,临时范围是调用qPrintable
的范围。