在尝试从QJsonArray
的值构造QString
时,我会收到以下错误:
error: passing 'const QString' as 'this' argument discards qualifiers [-fpermissive]
。
dunno在此代码中弄错了:
QString <CLASS_NAME>::getData(QString callerValue) {
QString BASE_URL = "<URL>";
QString stringToReturn = "";
QObject::connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {
QByteArray barr = reply->readAll();
QJsonParseError jpe;
QJsonDocument jdoc = QJsonDocument::fromJson(barr, &jpe);
QJsonArray synonymsArray = jdoc.array();
foreach (const QJsonValue &jv, synonymsArray) {
QJsonObject jo = jv.toObject();
QString s = jo.value("<VALUE>").toString();
stringToReturn.append(s + ", "); /* ERROR: The error above is from this line... */
}
}
);
request.setUrl(QUrl(BASE_URL + callerValue));
manager->get(request);
return stringToReturn;
}
这是另一个经典"我希望世界是同步的"问题。您不能以这种方式进行编码。getData
方法无法按照您想要的方式编写。getData
这样做会阻碍,这很浪费,可能会带来有趣的问题 - 不是最后一个可怕的UX。
根据您的应用程序,将有几个可能的修复程序:
-
使用Coroutines和
co_yield
重做getData
,以隐式延续风格进行重做 - 这是未来,除非您使用hacks这样的hacks,否则只能在最新的编译器上完成。 -
重做
getData
,以显式延续式通过样式, -
在可用数据时,用通知重做
getData
, -
有一个明确的状态计算机来处理您的代码进度。
延续风格需要最小的变化。请注意其他修复程序 - 最值得注意的是,您不应该使用QNetworkAccessManager
的信号:您仅对此查询的结果感兴趣,而不是每个查询!捕获QNetworkAccessManager::finished
信号只有在您真正拥有一个或至少可以处理最频繁的请求的中心点时才有用。在这种情况下,这是一个明智的优化:将第一个连接添加到无hiterto连接的对象上有几个malloc
s的开销。
void Class::getData(const QString &urlSuffix, std::function<void(const QString &)> cont) {
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
auto *reply = m_manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [=]{
QString result;
auto data = reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!result.isEmpty())
result.append(QLatin1String(", "))
result.append(s);
}
reply->deleteLater();
cont(result);
});
}
懒惰样式需要使用getData
的代码重新启动,并且只要连续连接连接到信号:
class Class : public QObject {
Q_OBJECT
QString m_cachedData;
QNetworkAccessManager m_manager{this};
Q_SIGNAL void dataAvailable(const QString &);
...
};
QString Class::getData(const QString &urlSuffix) {
if (!m_cachedData.isEmpty())
return m_cachedData;
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
auto *reply = m_manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, this, [=]{
m_cachedData.clear();
auto data = reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!m_cachedData.isEmpty())
m_cachedData.append(QLatin1String(", "))
m_cachedData.append(s);
}
reply->deleteLater();
emit dataAvailable(m_cachedData);
});
return {};
}
状态机正式为状态进展:
class Class : public QObject {
Q_OBJECT
QStateMachine m_sm{this};
QNetworkAccessManager m_manager{this};
QPointer<QNetworkReply> m_reply;
QState s_idle{&m_sm}, s_busy{&m_sm}, s_done{&m_sm};
Q_SIGNAL void to_busy();
void getData(const QString &);
...
};
Class::Class(QObject * parent) : QObject(parent) {
m_sm.setInitialState(&s_idle);
s_idle.addTransition(this, &Class::to_busy, &s_busy);
s_done.addTransition(&s_idle);
m_sm.start();
}
void Class::getData(const QString &urlSuffix) {
static char const kInit[] = "initialized";
auto const urlString = QStringLiteral("URL%1").arg(urlSuffix);
QNetworkRequest request(QUrl(urlString));
m_reply = m_manager.get(request);
s_busy.addTransition(reply, &QNetworkReply::finished, &s_done);
to_busy();
if (!s_done.property(kInit).toBool()) {
QObject::connect(&s_done, &QState::entered, this, [=]{
QString result;
auto data = m_reply->readAll();
QJsonParseError jpe;
auto jdoc = QJsonDocument::fromJson(data, &jpe);
auto const synonyms = jdoc.array();
for (auto &value : synonyms) {
auto object = value.toObject();
auto s = object.value("<VALUE">).toString();
if (!result.isEmpty())
result.append(QLatin1String(", "))
result.append(s);
}
m_reply->deleteLater();
});
s_done.setProperty(kInit, true);
}
}
当然是错误的: stringToReturn
被声明为 getData
中的局部变量,如果您使用 [=]
,它将是const,如果通过参考捕获。lambda表达式将在其中有一个悬而未决的参考。这是将作为此功能对象输出的变量的不良位置,该变量在从getData
返回时停止存在。
lambda表达式创建的函数对象在返回 getData
之后称为。它被称为当发送请求引起信号时,它是一个异步处理程序。在这种情况下,GetData不是Lambda的来电者。Lambda的来电者是信号插槽系统。只要GetData没有明确调用lambda,我们就不能保证在本地存储的寿命结束之前返回函数对象。
可能的remebdy是使用this
的字段,如果您可以保证当finished()
发射CC_23时this
(<CLASS_NAME>
实例(仍然"活着"。本质上,除非您暂停该值,否则此" GetData"无法返回该值(在请求完成之前(打败异步方法(。
实际上,当QNetworkReply::finished
发射时,finished
将被解雇,qnetworkAccessManager :: feet oft post post请求并返回后立即回复。收到数据时发射信号(发射ReadyRead(