qPrintable是否容易发生访问冲突?

时间:2016-04-08 12:55:28

标签: c++ qt

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())

在被调用函数内部,两个参数都是指向同一地址的指针。

3 个答案:

答案 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的范围。