尝试从QString
的值构建QJsonArray
时,出现以下错误:
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;
}
答案 0 :(得分:2)
这是另一个经典的“我希望世界同步”的问题。你不能这样编码。 getData
方法无法按您希望的方式编写。 getData
以这种方式阻止,这非常浪费并且可能导致有趣的问题 - 而不是最后一个是可怕的用户体验。
根据您的应用程序,可能会有几种可能的修复方法:
redo getData
使用协程和co_yield
隐式延续传递样式 - 这是未来,只能在最新的编译器上完成,除非你使用诸如boost协程之类的黑客。 / p>
以明确的连续传递方式重做getData
,
以懒惰样式重做getData
,并在数据可用时发出通知,
有一个明确的状态机来处理代码的进度。
延续传递样式需要的变化最少。另请注意其他修复 - 最值得注意的是,您不应该使用QNetworkAccessManager
的信号:您只对这一个查询的结果感兴趣,而不是每个查询!仅当您确实拥有可以处理所有或至少最常见请求的中心点时,捕获QNetworkAccessManager::finished
信号才有用。在这种情况下,这是一个明智的优化:将几个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);
}
}
答案 1 :(得分:1)
当然这是错误的:stringToReturn
被声明为getData
中的局部变量,如果你使用[=]
它将是const并且它会在函数对象时死掉# 39;通过finished
信号调用,如果通过引用捕获。 Lambda表达式中会有一个悬空引用。放置变量作为此函数对象的输出是个不好的地方,该变量在从getData
返回时停止存在。
此处由lambda表达式创建的函数对象在 getData
返回后称为。当信号因发送请求而被触发时,它将被称为 sometime ,它是一个异步处理程序。在这种情况下,getData不是lambda的调用者。 lambda的调用者是信号槽系统。如果getData没有显式调用lambda,我们无法保证在本地存储的生命周期结束之前返回函数对象。
如果你可以保证this
(this
个实例)仍然是“活着的”,那么这里可能的回忆就是使用<CLASS_NAME>
的字段。何时finished()
被解雇。本质上这是&#34; getData&#34;除非你在请求完成之前暂停它(这会使异步方法失败),否则无法返回该值。
实际上,当finished
被触发时,QNetworkReply::finished
会被触发,QNetworkAccessManager ::只是发布请求并立即返回所述回复。收到数据时会触发信号(发出readyRead)