Проблемы с созданием массива char из QMap из QString - PullRequest
0 голосов
/ 14 мая 2018

Я использую библиотеку libxslt C, и мне нужно передать параметры как const char *. Я оборачиваю библиотеку в класс Qt C ++, поэтому параметры, хранящиеся в классе C ++, сохраняются как QMap<QString, QString>.

Моя первая попытка была просто:

const char *params[32];
int index = 0;
if (m_params.size() > 0) {
    QMapIterator<QString, QString> it(m_params);
    while (it.hasNext()) {
        it.next();

        params[index++] = it.key().toLocal8Bit().data();

        params[index++] = it.value().toLocal8Bit().data();
    }
}

params[index++] = nullptr;

qDebug() << params[0] << params[1]; // 0 0

Но я понимаю, что это не работает, потому что QByteArray из toLocal8bit выходит из области видимости почти сразу, как только я его использую.

Я пытался использовать strcpy, но у меня были те же проблемы с областью действия:

m_params.insert("some-key", "some-value", "another-key", "another-value");

if (m_params.size() > 0) {
    QMapIterator<QString, QString> it(m_params);
    while (it.hasNext()) {
        it.next();

        char buffer[32];

        strcpy(buffer, it.key().toLocal8Bit().data());
        params[index++] = buffer;

        strcpy(buffer, it.value().toLocal8Bit().data());
        params[index++] = buffer;
    }
}

params[index++] = nullptr;

qDebug() << params[0] << params[1]; // another-value another-value

Так что теперь у меня есть список параметров с одинаковым значением.

Когда я устанавливаю все значения вручную, я получаю ожидаемые результаты:

const char *params[32];
int index = 0;

params[index++] = "something";
params[index++] = "something-else";

params[index++] = nullptr;

qDebug() << params[0] << params[1]; // something something-else

1 Ответ

0 голосов
/ 14 мая 2018

Это достаточно просто - вам нужно убедиться, что буфер для параметров сохраняется достаточно долго. Не используйте массивы фиксированного размера - вы настраиваете себя на переполнение буфера.

class Params {
  QByteArray buf;
  QVector<const char *> params;
public:
  Params() = default;
  template <class T> explicit Params(const T& map) {
    QVector<int> indices;
    indices.reserve(map.size());
    params.reserve(map.size()+1);
    for (auto it = map.begin(); it != map.end(); ++it) {
      indices.push_back(buf.size());
      buf.append(it.key().toLocal8Bit());
      buf.append('\0');
      indices.push_back(buf.size());
      buf.append(it.value().toLocal8Bit());
      buf.append('\0');
    }
    for (int index : qAsConst(indices))
      params.push_back(buf.constData() + index);
    params.push_back(nullptr);
  }
  operator const char **() const { return const_cast<const char**>(params.data()); }
  operator const char *const*() const { return params.data(); }
  operator QVector<const char*>() const { return params; }
};

void MyClass::method() const {
  Params params{m_params};
  ...
  res = xsltApplyStylesheet(cur, doc, params);
  ...
}
...