Russian Qt Forum

Qt => Общие вопросы => Тема начата: SABROG от Май 28, 2007, 09:11



Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 09:11
Я пишу программу, которая работает с XMLем, парсер создает дерево XMLя в памяти, где ветки имеют указатели на данные, ключи и параметры типа unsigned char. Т.к. XML это большой массив текстовых данных в памяти, то мне бы не хотелось для работы с этими данными весь текст копировать опять но уже в класс QString. Возможно ли создать экземпляр объекта класса QString куда можно передать только указатель на текстовую zero-null строку в формате UTF8, таким образом чтобы доступ к ней осуществлялся как по обычному указателю (unsigned char *) так и через класс QString ? Т.е. если я что-то меняю через указатель (unsigned char *), то строка в классе QString тоже будет менятся. Нужно это все для экономии памяти и скорости при работе с XMLем.

добавлено спустя 8 минут:

 Вроде нашел решение:

Цитировать

QString QString::fromRawData ( const QChar * unicode, int size )   [static]
Constructs a QString that uses the first size Unicode characters in the array unicode. The data in unicode is not copied. The caller must be able to guarantee that unicode will not be deleted or modified as long as the QString (or an unmodified copy of it) exists.
Any attempts to modify the QString or copies of it will cause it to create a deep copy of the data, ensuring that the raw data isn't modified.
Here's an example of how we can use a QRegExp on raw data in memory without requiring to copy the data into a QString:
      QRegExp pattern;
      static const QChar unicode[] = {
              0x005A, 0x007F, 0x00A4, 0x0060,
              0x1009, 0x0020, 0x0020};
      int size = sizeof(unicode) / sizeof(QChar);

      QString str = QString::fromRawData(unicode, size);
      if (str.contains(QRegExp(pattern))) {
          // ...
      }
Warning: A string created with fromRawData() is not '\0'-terminated, unless the raw data contains a '\0' character at position size. This means unicode() will not return a '\0'-terminated string (although utf16() does, at the cost of copying the raw data).


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Alex03 от Май 28, 2007, 11:50
Ежели у Вас данные в UTF-8 то оно никак с const QChar * unicode не кореллирует.
Возможно Вам подойдёт QCString?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 12:44
QCString уже не поддерживается:

Цитировать

Q3CString(const char *str, uint max) constructs a string of length strlen(str) or max - 1, whichever is shorter. QByteArray(const char *data, int size) constructs a byte array containing exactly size bytes.
For example, if you have code like
     QCString str1("Hello", 4);           // "Hel"
     QCString str2("Hello world!", n);
you can rewrite it as
     QByteArray str1("Hello", 3);
     QByteArray str2("Hello world!");
     str2.truncate(n - 1);


Еще такой вопрос. Есть у меня метод:

Код:
QString & TForm::escaped(QString &sql)
{
    return sql.replace(QLatin1String("'"),QLatin1String("''")).prepend(QLatin1String("'")).append(QLatin1String("'"));
}


Я пытаюсь в него передать строку таким макаром:
Код:

main->escaped( leEditBox->text() );


Но получаю ошибку, что нельзя преобразовать QString в QString&. Я почему-то всегда считал, что указывая непосредственно экземпляр класса я неявно передаю ссылку на него:

Код:

QString txt = "HOTEL'S";
escaped(txt);


Этот кусок работает как надо, также как и этот:

Код:

QString leEditBoxText(leEditBox->text());
main->escaped( leEditBoxText );


Почему же без посредников не компилит ?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Tonal от Май 28, 2007, 13:03
const в сигнатуре функции забыл.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 13:20
Сделал так:

Код:

QString & TForm::escaped(const QString &sql)


Только ругается на эту строку:

Код:

return sql.replace(QLatin1String("'"),QLatin1String("''")).prepend(QLatin1String("'")).append(QLatin1String("'"));


Цитировать

src\TForm.cpp: In member function `QString& TForm::escaped(const QString&)':
src\TForm.cpp:1355: error: passing `const QString' as `this' argument of `QStrin
g& QString::replace(const QString&, const QString&, Qt::CaseSensitivity)' discar
ds qualifiers


Понять не могу че ему не нравится.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: pastor от Май 28, 2007, 13:43
Цитата: "SABROG"

Понять не могу че ему не нравится.


У тебя оъявлена константная ссылка на объект. При этом,  значение этого объекта не может быть изменено. По сути, это объявление делает константным сам объект.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Май 28, 2007, 13:45
Хмм?
Код:
QString tmp = sql;
return tmp.replace (...);


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Май 28, 2007, 13:48
все верно, sql у тя константа теперь, а метод QString::replace не имеет модификатора const. Т.е. он должен изменять sql, но она же у тебя константная.
делай как Вудруф говорит.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 14:00
В заблуждение меня вводите :P
Сделал как Вудруф предложил, думал replace создает новый объект класса QString, а старый оставляет неизменным. Ну раз это не так, то действительно оригинальные строки лучше оставлять неизменными, тем более что возможна передача константных объектов.

Еще вот чего я понять не могу:

Код:

QString & TForm::escaped(const QString &sql)
{
    QString tmp = sql;
    return tmp.replace(QLatin1String("'"),QLatin1String("''")).prepend(QLatin1String("'")).append(QLatin1String("'"));
}


Если я создаю объект класса QString в стеке, то при выходе из процедуры он должен уничтожится и вернется ссылка на несуществующий объект, разве нет ? Угу, значит надо через new делать, но вот кто будет потом освобождать память, мне влом как-то :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Май 28, 2007, 14:56
Возвращай в таком случае сам объект а не ссылку на него.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Май 28, 2007, 15:08
как вариант сделай
void TForm::escaped(QString &sql)
{
sql = sql.replace(QLatin1String("'"),QLatin1String("''")).prepend(QLatin1String("'")).append(QLatin1String("'"));}

и передавай в качестве параметра строку, которая должна модифицироваться...


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 16:09
Спасибо за варианты. Я сделал как предложил goer, все-таки у меня возможна передача константных строк, которым нельзя сделать replace. А учитывать это каждый раз в коде копируя строки не хочется. Поэтому пусть уж копируются  внутри процедуры.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Май 28, 2007, 16:45
А чтобы SABROG не мучала совесть по поводу эффективности использования копирования строк, могу сообщить ему что в кути применяется такая замечательнаяя технология как Implicitly Sharing, из за которой глубокого копирования при возвращении строки не будет. Скопируется только указатель на данные, которым и завладеет объект-получатель значения функции.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 16:57
Насчет deep copying я почитал и понял такую вещь, если нигде в коде не меняются данные переданные из одного QString в другой QString, то копирования не происходит, но если же происходят операции со строками, то да, идет "глубокое копирование"


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Mikhail от Май 28, 2007, 19:31
to SABROG

Цитировать

Еще такой вопрос. Есть у меня метод:
Код:
QString & TForm::escaped(QString &sql)
{
    return sql.replace(QLatin1String("'"),QLatin1String("''")).prepend(QLatin1String("'")).append(QLatin1String("'"));
}



Я пытаюсь в него передать строку таким макаром: Код:

main->escaped( leEditBox->text() );



Но получаю ошибку, что нельзя преобразовать QString в QString&. Я почему-то всегда считал, что указывая непосредственно экземпляр класса я неявно передаю ссылку на него:
Код:

QString txt = "HOTEL'S";
escaped(txt);


Вопрос в том какой у тебя компилятор.
Если MSVC то он проглотит оба варианта.
Скорее всего у тебя MinGW либо gcc


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 28, 2007, 21:35
Верно, у меня gcc (MinGW). Тяжела и неказиста жить простого программиста, язык один на всех, а писать код приходится в итоге под компилятор :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Май 29, 2007, 13:43
Цитировать
Если я создаю объект класса QString в стеке, то при выходе из процедуры он должен уничтожится и вернется ссылка на несуществующий объект, разве нет ?

Цитировать
Возвращай в таком случае сам объект а не ссылку на него.

Верно, я проглядел. Нужно возвращать копию объекта, а не ссылку на него (тем более, что для QString это совсем не дорого...).

Цитировать
Но получаю ошибку, что нельзя преобразовать QString в QString&.

На самом деле ошибка в другом - ты передаёшь временный объект (а leEditBox -> text() таковой, похоже, и возвращает) по ссылке (причём не по константной!).
Хотя ошибка-то должна возвращаться более понятная, похожая на эту:
Код:
error: invalid initialization of non-const reference of type 'int&' from a temporary of type 'int'

Именно для этого и нужен был const для параметра. Если приведённый выше код проглатывает VS... то это плохой компилятор :) Он позволяет тебе модифицировать данные, которые всё равно будут удалены :)
Вообще-то по стандарту такое поведение не допускается.
Далее: мы не только не можем передавать в функцию по ссылке временную переменную, мы не можем и вызвать конструктор вместо передачи параметра, т.к. опять же передаём в функцию временный объект (не привязанный ни к какой переменной).
Хуже другое: мы не можем определить переменную только для вызова:
Код:

class HostsInfo
{
public:
    void readInfo (std::istream &);
...
};

Вызываю:
a.readInfo (std::ifstream stream ("settings.ts"));

Т.к. это не допустимо. Это плохо, т.к. приходится делать так:
Код:

std::ifstream stream ("settings.ts");
a.readInfo (stream);

А это не закрывает поток вплоть до окончания содержащего блока. Мы, конечно, можем закрыть его сами, но экземпляр всё равно будет жить до конца блока и отжирать память.

Выход есть - создавать отдельный блок только для вызова функции:
Код:

{ //начало, скажем функции
  ...
  { //наш дополнительный блок
    std::ifstream stream ("settings.ts");
    a.readInfo (stream);
  }
  ...
}

Но это, ИМХО, некрасиво. Своего рода ХАК :(


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 29, 2007, 21:59
В продолжение темы оптимизации работы со строками хотелось бы спросить.
Мой тестовый XML содержит данных на 154740 строк таблицы, в которой 7 колонок.
Я работаю с SQLITE базой, в таблице все данные числовые, естественно, чтобы в таблицу что-то положить - надо составить SQL запрос - INSERT. Пробежавшись по дереву XMLя я заполнил QList экземплярами структуры, где содержится 7 указателей на строку unsigned char. Т.е. количество элементов в QListe 154740, а общее количество указателей на текстовые данные 154740*7=1083180 указателей на строки, где содержатся числа. Этот цикл у меня выполняется 9 секунд (выполняется 154740 раз):

Код:

                for (int i=0; i < listPrice.size(); i++)
                {
                    QString hotel = QString::fromUtf8((const char *)listPrice.at(i).hotel);
                    QString room = QString::fromUtf8((const char *)listPrice.at(i).room);
                    QString place = QString::fromUtf8((const char *)listPrice.at(i).place);
                    QString meal = QString::fromUtf8((const char *)listPrice.at(i).meal);
                    QString night = QString::fromUtf8((const char *)listPrice.at(i).night);
                    QString checkin = QString::fromUtf8((const char *)listPrice.at(i).checkin);
                    unsigned int ts = QDateTime::fromString(checkin, "yyyyMMdd").toTime_t();
                    QString price = QString::fromUtf8((const char *)listPrice.at(i).price);
                    qList << QString("INSERT INTO price (hotel, room, place, meal, night, checkin, price) VALUES (%1,%2,%3,%4,%5,'%6',%7);").arg(hotel).arg(room).arg(place).arg(meal).arg(night).arg(ts).arg(price);

                }


Потом я передаю QStringList с инсертами в SQLITE базу и выполняется все это 30 секунд. Ну с базой ладно, хрен с ней, ее скорость на совести разработчика. А вот то что формирование инсертов выполняется так медленно меня не очень устраивает. Может быть есть более быстрые способы "склеить" строки (unsigned char), а потом уже сконвертить в QString ?

P.S.: Кстати парадокс заполненная база SQLITE весит почти столько же сколько и XML файл, хотя я провел все возможные оптимизации, уж не знаю какой хрени туда еще пихает движок:

Xml - 6 596 125 байт
база - 6 538 240 байт

Только вот еще обидно, что Xml то жмется до 500 килобайт, а база жмется всего до 1.5 мегабайта.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Май 30, 2007, 11:55
Ну во-первых так:
Код:

QString query = "INSERT INTO price (hotel, room, place, meal, night, checkin, price) VALUES (";
query += hotel;
query += ",";
query += room;
query += ",";
query += place;
query += ",";
query += meal;
query += ",";
query += night;
query += ",";
query += ts;
query += ",";
query += price;
query += ");";

Конечно, вариант с %1 гораздо удобнее, но (увы!) медленнее.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 30, 2007, 14:46
С %1 - 11453 мс
С +   - 11110 мс


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Май 30, 2007, 14:52
Впечатляет :-)


А может попробовать через бинды в запросе?

Код:
void QSqlQuery::bindValue ()


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 30, 2007, 15:11
Это ново для меня. В чем состоит смысл bindValue ?

Можно ли сделать так например:

Код:

QSqlQuery query;
     query.prepare("INSERT INTO person (id, forename, surname) "
                   "VALUES (:id, :forename, :surname)");
     query.bindValue(":id", 1001);
     query.bindValue(":forename", "Bart");
     query.bindValue(":surname", "Simpson");
     query.exec();
     query.bindValue(":id", 1002);
     query.bindValue(":forename", "Vasya");
     query.bindValue(":surname", "Pupkin");
     query.exec();


Т.е., например, я отправляю на сервер запрос "INSERT INTO person (id, forename, surname) VALUES (:id, :forename, :surname)", а потом досылаю еще данных на 154740 инсертов, но на сервер отправляются только двоичные данные. Или драйвер все-таки сделает автозамену прежде чем что-то отослать ?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Май 30, 2007, 15:33
Ну как я понимаю данные "отсылаются" только во время query.exec();.
А bindValue() просто вставляет данные в запрос. Очень удобная штука: например через QString/arg никак не засунешь в запрос BLOB-ы, а бинд хавает все, ибо использует QVariant.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 30, 2007, 16:26
Т.е., в принципе, это никак не повлияет на скорость заполнения таблицы ?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Май 30, 2007, 16:46
На скорость заполнения будет влиять время бинда(локальные затраты процесса) и время выполнения запроса(локальные затраты процесса + скорость работы сиквеля)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 30, 2007, 17:03
Врятли бинд быстрее операции конкатенации :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Май 31, 2007, 00:39
Смотри:

1.выносишь за цикл это:

QString request = QString("INSERT INTO price (hotel, room, place, meal, night, checkin, price) VALUES (%1,%2,%3,%4,%5,'%6',%7);");

Оно у тебя каждый раз в цикле создается, а это уже 154740 созданий строки... то есть вызовы самых медленных операций аллокации...

2. строки типа QString hotel = QString::fromUtf8((const char *)listPrice.at(i).hotel) тоже идут лесом. У тебя опять создание локальных строк, плюс еще конверсия в и из const char *.

3. в цикле делаешь бинды данных к request, а потом выполняешь запрос. Вряд ли с QStringList будет быстрее, скорее наоборот...

добавлено спустя 5 минут:

 имею в виду - запрос тоже в цикле.
прибиндил данные - выполнил запрос
и так 154740 раз :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Май 31, 2007, 07:45
Для Oracle использование связывания может прилично ускорить выполнение запроса, т.к. оптимизируется он один раз, а выполняется - много. Но SQLite - база лёгкая...

А про скорость приведённого выше кода: основная проблема в fromUtf8.
Лично я вчера решил протестировать, насколько мой (с +=) будет быстрее, чем через %1. На 1000000 итераций первый способ работал 5 секунд, в то время как второй - 15. Так что ускорение создания строки в три раза - результат.

добавлено спустя 4 минуты:

 
Цитировать
Ну как я понимаю данные "отсылаются" только во время query.exec();

Не факт. В хорошем случае запрос и параметры передаются отдельно. Скажем, так делает Pear :: DB, но как это сделано в Qt - смотреть надо.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 31, 2007, 08:40
Заинтересовал еще такой вариант:

Цитировать

bool QSqlQuery::execBatch ( BatchExecutionMode mode = ValuesAsRows )
Executes a previously prepared SQL query in a batch. All the bound parameters have to be lists of variants. If the database doesn't support batch executions, the driver will simulate it using conventional exec() calls.
Returns true if the query is executed successfully; otherwise returns false.
Example:
 QSqlQuery q;
 q.prepare("insert into myTable values (?, ?)");

 QVariantList ints;
 ints << 1 << 2 << 3 << 4;
 q.addBindValue(ints);

 QVariantList names;
 names << "Harald" << "Boris" << "Trond" << QVariant(QVariant::String);
 q.addBindValue(names);

 if (!q.execBatch())
     qDebug() << q.lastError();
The example above inserts four new rows into myTable:
 1  Harald
 2  Boris
 3  Trond
 4  NULL
To bind NULL values, a null QVariant has to be added to the bound QVariantList, for example: QVariant(QVariant::String)
Note that every bound QVariantList must contain the same amount of variants. Note that the type of the QVariants in a list must not change. For example, you cannot mix integer and string variants within a QVariantList.
The mode parameter indicates how the bound QVariantList will be interpreted. If mode is ValuesAsRows, every variant within the QVariantList will be interpreted as a value for a new row. ValuesAsColumns is a special case for the Oracle driver. In this mode, every entry within a QVariantList will be interpreted as array-value for an IN or OUT value within a stored procedure. Note that this will only work if the IN or OUT value is a table-type consisting of only one column of a basic type, for example TYPE myType IS TABLE OF VARCHAR(64) INDEX BY BINARY_INTEGER;
This function was introduced in Qt 4.2.


Т.е. я могу в цикле заполнить QVariantList , потом в конце выполнить все.

По поводу fromUtf8, я еще точно сам не определился что мне лучше использовать, толи fromUtf8, толи fromLocal8bit. А преобразование (const char *) врятли что-то меняет вообще, я просто говорю компилятору, что это указатель не типа xmlChar, а const char, что идентично, т.к. в хидерах libxml2 xmlChar это и есть const char.

С конкатенацией плюсиком я еще раз протестирую, возможно я что-то сделал не так. Я делал так:

QString insertPart = a + b + c + d + e;

Не думал что есть разница с этим:

QString insertPart = a;
a += b;
a += c;
a += d;

Перепроверю.
---
Проверил разница снова не более 300 мс.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Май 31, 2007, 12:45
в даном примере разницы не будет вообще.
это те же самые операции.
когда они записаны подряд одной строкой - они все равно вызываются по очереди.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Май 31, 2007, 22:05
Сделал проверку. Вот код:

Код:

/// TEST SECTION BEGIN
listExec(dbSPO,qList);
QTime tt1,tt2,tt3;
QVariantList thotels,trooms,tplaces,tmeals,tnights,tcheckins,tprice;
QSqlQuery tq(dbSPO);
/*
Inc int
Hotel int
Room int
Place int
Meal int
Night int
Checkin int
Price float
*/
tq.prepare("insert into price (hotel,room,place,meal,night,checkin,price) values (?,?,?,?,?,?,?);");
tt2.start();
xmlChar *tstr = (xmlChar *)"1234";
        for (int i=0; i < 154740; i++)
        {
            thotels << QString((const char *)tstr);
            trooms << QString((const char *)tstr);
            tplaces << QString((const char *)tstr);
            tmeals << QString((const char *)tstr);
            tnights << QString((const char *)tstr);
            tcheckins << QString((const char *)tstr);
            tprice << QString((const char *)tstr);
        }
qDebug("Generate queries: %d ms", tt2.elapsed());
tt3.start();
        tq.addBindValue(thotels);
        tq.addBindValue(trooms);
        tq.addBindValue(tplaces);
        tq.addBindValue(tmeals);
        tq.addBindValue(tnights);
        tq.addBindValue(tcheckins);
        tq.addBindValue(tprice);
qDebug("Bind values: %d ms", tt3.elapsed());
tt1.start();
if (!tq.execBatch())
     qDebug() << tq.lastError();
qDebug("Execute queries: %d ms", tt1.elapsed());
return true;
/// TEST SECTION END


Результат:

[31.05.07 22:58:52] [D] Generate queries: 1625 ms
[31.05.07 22:58:52] [D] Bind values: 0 ms
[31.05.07 23:00:53] [D] Execute queries: 120343 ms

Понравилась скорость генерирования запросов. Но вот 120 секунд на выполнение запроса, у меня сейчас запрос из 154740 строк вида "INSERT INTO .." в QStringList выполняется за 30 секунд, но вполне возможно, что это из-за того, что я не включил транзакцию.

Щас буду замерять скорость генерирования INSERTов отдельно от парсинга xmlя.

Такой тест еще провел:

Код:

/// TEST SECTION BEGIN 2
listExec(dbSPO,qList);
qList.clear();
QTime tt1,tt2;
tt2.start();
xmlChar *tstr = (xmlChar *)"1234";
        for (int i=0; i < 154740; i++)
        {
            qList << QString("INSERT INTO price (hotel,room,place,meal,night,checkin,price) VALUES (%1,%2,%3,%4,%5,%6,%7);")
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr))
            .arg(QString((const char *)tstr));
        }
qDebug("Generate queries: %d ms", tt2.elapsed());
tt1.start();
listExec(dbSPO,qList);
qDebug("Execute queries: %d ms", tt1.elapsed());
return true;
/// TEST SECTION END 2


Результаты:
[31.05.07 23:24:18] [D] Generate queries: 2750 ms
[31.05.07 23:24:36] [D] Execute queries: 18438 ms

Щас для первого теста попробую транзакцию включить.

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

Код:

dbSPO.transaction();
if (!tq.execBatch())
     qDebug() << tq.lastError();
dbSPO.commit();


[31.05.07 23:30:33] [D] Generate queries: 1469 ms
[31.05.07 23:30:33] [D] Bind values: 0 ms
[31.05.07 23:30:39] [D] Execute queries: 6484 ms


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Июнь 01, 2007, 08:13
Цитировать
в даном примере разницы не будет вообще

Почему это? Вариант a+b+c+d+e создаёт временные переменные, вариант с += - не создаёт.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Июнь 01, 2007, 08:48
Цитировать

Вариант a+b+c+d+e создаёт временные переменные, вариант с += - не создаёт.


Совершенно не факт. И в первом примере можно обойтись без временных переменных. Особенно если оптимизация компиля включена.

А вот уважаемый SABROG таки оптимизировал свой код :) Молодец :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Tonal от Июнь 01, 2007, 10:14
Цитата: "SABROG"
Включил транзакцию, результаты первого теста превзлошли все мои ожидания:
Код:

dbSPO.transaction();
if (!tq.execBatch())
     qDebug() << tq.lastError();
dbSPO.commit();


[31.05.07 23:30:33] [D] Generate queries: 1469 ms
[31.05.07 23:30:33] [D] Bind values: 0 ms
[31.05.07 23:30:39] [D] Execute queries: 6484 ms

Т.е. время выполнения запроса превышает время его генерации от 5-ти раз в лучшем случае до 2-х порядков ...
Не кажется ли тебе, что ты что-то не то оптимизируешь? ;-)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 01, 2007, 10:28
Ну движок SQLITE'a я оптимизировать врятли смогу, исходники есть конечно, но у меня своих тараканов в голове полно :)

Еще я думал, что если из XMLя данные перенесу в базу, то база будет в несколько раз меньше весить чем XML, все-таки числа не строки. Но был разочарован, размер почти такой же у файла. А был еще больше, пришлось отказаться от типа данных DATE,DATETIME, т.к. все даты в SQLITE хранятся в виде текста, поставил intы и использую поле как unix timestamp.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Tonal от Июнь 01, 2007, 11:19
Если нужно максимально компактно - можно XML упаковать. Или свой бинарный формат изобресть. ;-)
А движок базы оптимизирован по скорости выборок, а не по размеру данных.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Вудруф от Июнь 01, 2007, 11:19
С другой стороны выборка информации из базы данных происходит явно быстрее, чем из XML-файла. Да и изменение тоже.
Так что нечего горевать о большом размере, плюсов-то гораздо больше.

У нас вон база несколько гигов занимает, и ничего, не страдаем :)


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 01, 2007, 12:34
Просто у меня планы были, организовать обмен SQLITE базами между компаниями, вместо неудобного XMLя. Сжимаемость SQLITE баз в 3 раза хуже чем у текстового XMLя, а значит все-таки траффика будет расходываться больше. Но да, плюсы в том, что можно сделать выборку тут же без парсинга и положить данные в основную базу.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Tonal от Июнь 01, 2007, 21:11
Если таки обмен то зачем выборки?
Парсешь всё SAX-ом и заливаешь по ходу. Ну может какую фильтрацию делаешь.
Обменные форматы вроде бы под обмен м затачиваются - чтоб без особых раздумий  и тормозов сгенерить и влить...


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 04, 2007, 11:29
Заметил, что часто в исходниках Qt используется QLatin1String:

Код:

QDebug operator<<(QDebug debug, QDir::Filters filters)
{
    QStringList flags;
    if (filters == QDir::NoFilter) {
        flags << QLatin1String("NoFilter");
    } else {
        if (filters & QDir::Dirs) flags << QLatin1String("Dirs");
        if (filters & QDir::AllDirs) flags << QLatin1String("AllDirs");
        if (filters & QDir::Files) flags << QLatin1String("Files");
        if (filters & QDir::Drives) flags << QLatin1String("Drives");
        if (filters & QDir::NoSymLinks) flags << QLatin1String("NoSymLinks");
        if (filters & QDir::NoDotAndDotDot) flags << QLatin1String("NoDotAndDotDot");
        if ((filters & QDir::AllEntries) == QDir::AllEntries) flags << QLatin1String("AllEntries");
        if (filters & QDir::Readable) flags << QLatin1String("Readable");
        if (filters & QDir::Writable) flags << QLatin1String("Writable");
        if (filters & QDir::Executable) flags << QLatin1String("Executable");
        if (filters & QDir::Modified) flags << QLatin1String("Modified");
        if (filters & QDir::Hidden) flags << QLatin1String("Hidden");
        if (filters & QDir::System) flags << QLatin1String("System");
        if (filters & QDir::CaseSensitive) flags << QLatin1String("CaseSensitive");
    }
    debug << "QDir::Filters(" << qPrintable(flags.join(QLatin1String("|"))) << ")";
    return debug;
}


Почитав описание, я так понял, что отличие его от QString в том, что QString делает копирование строки, а QLatin1String использует уже имеющийся указатель. Там даже есть такой пример:

Код:

 QLabel *label = new QLabel(QLatin1String("MOD"), this);


Т.е. если я запишу так, то строка "MOD" продублируется ?
Код:

 QLabel *label = new QLabel("MOD", this);


А как же implicit sharing ?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Июнь 04, 2007, 12:13
Цитировать
Почитав описание, я так понял, что отличие его от QString в том, что QString делает копирование строки


Assitant:

Цитировать
The QLatin1String class provides a thin wrapper around an ASCII/Latin-1 encoded string literal.


и дальше:

Applications that define QT_NO_CAST_FROM_ASCII don't have access to QString's const char * API, следовательно им нужно вызывать конструкторы копирования, присванивание и прочие "тяжелые" операции, для того чтобы "кастить" char* к QString. Вместо этого предлагают использовать QLatin1String для избежания этих тяжелых опраций и одновременно работой с char* как с QString.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 04, 2007, 12:59
Ну я не определял нигде QT_NO_CAST_FROM_ASCII, значит мне не надо использовать QLatin1String. А почему тогда тролли его используют, если его можно не использовать не понятно.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Июнь 04, 2007, 14:04
Потому что он "thin" :-)

Можно например юзать QTimer или QBasicTimer. Если QBasicTimer удовлетворяет потребностям, почему бы не заюзать его как более легкий класс.

Вообще не думаю что в бизнес-апликухах это столь важно, а для серьезных вычислений никто кути использовать не будет.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 04, 2007, 14:27
Ну "thin" переводится как "тонкий", т.е. все дело в экономии на отведение памяти под класс ?

А что используют под серьезные вычисления ? Чистый Си и Intel Compiler :) ?


Название: Как в QString сменить указатель на массив данных ?
Отправлено: goer от Июнь 04, 2007, 14:37
Иногда даже специальное железо. Хотя в последнее время "иногда" стало очень частым явлением.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: Racheengel от Июнь 04, 2007, 22:00
Qt для гуя юзают обычно, а не для вычислений :))


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 04, 2007, 22:58
Так ведь никто не запрещает при этом вычислять, не используя классы Qt.

Сегодня полностью перевел парсер на код, который дал лучшие результаты (addBindValue и иже с ними). По какой-то неизвестной причине теперь все парсится и кладется в базу еще дольше, чем с формированием INSERTов. Причем видимой разницы никакой, в тестовом куске QVariantListы содержат 150т.с записей и после парсинга мои QVariantListы тоже содержат  это же количество записей, тестовый кладется за 6.5 секунд, а реальный за 30 секунд. Еще, как назло, выяснилось, что если в SQLITE базе вручную не создать индексы на все поля использующиеся в WHERE и ORDER BY, то запросы выполняются по неизвестное мне количество минут (дольше 15 минут не выдерживал). С индексами все моментально, правда база теперь разрослась с 6 мегабайт до 10 и весит в 2 раза больше чем исходный XMLфайл, ну и 150 т.записей кладутся уже 40 секунд.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: joktar от Июнь 05, 2007, 12:45
Видиокарту например (смотри www.gpugpu.org,www.rapidmind.net,)
но это именно для "математики" с большими объемами числовых данных.


Название: Как в QString сменить указатель на массив данных ?
Отправлено: SABROG от Июнь 05, 2007, 12:52
Вообще странно, что эту тему начали развивать. Меня не столько интересует скорость вычислений, сколько загрузки данных в базу и парсинг XMLя :P

Я правильно понимаю, на rapidmind предлагают софт с API функциями для математических вычислений используя GPU процессор видеокарты ?