Russian Qt Forum
Октябрь 05, 2024, 18:22 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4   Вниз
  Печать  
Автор Тема: Как в QString сменить указатель на массив данных ?  (Прочитано 27294 раз)
SABROG
Гость
« Ответ #15 : Май 28, 2007, 21:35 »

Верно, у меня gcc (MinGW). Тяжела и неказиста жить простого программиста, язык один на всех, а писать код приходится в итоге под компилятор Улыбающийся
Записан
Вудруф
Гость
« Ответ #16 : Май 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);
  }
  ...
}

Но это, ИМХО, некрасиво. Своего рода ХАК Грустный
Записан
SABROG
Гость
« Ответ #17 : Май 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 мегабайта.
Записан
Вудруф
Гость
« Ответ #18 : Май 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 гораздо удобнее, но (увы!) медленнее.
Записан
SABROG
Гость
« Ответ #19 : Май 30, 2007, 14:46 »

С %1 - 11453 мс
С +   - 11110 мс
Записан
goer
Гость
« Ответ #20 : Май 30, 2007, 14:52 »

Впечатляет :-)


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

Код:
void QSqlQuery::bindValue ()
Записан
SABROG
Гость
« Ответ #21 : Май 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 инсертов, но на сервер отправляются только двоичные данные. Или драйвер все-таки сделает автозамену прежде чем что-то отослать ?
Записан
goer
Гость
« Ответ #22 : Май 30, 2007, 15:33 »

Ну как я понимаю данные "отсылаются" только во время query.exec();.
А bindValue() просто вставляет данные в запрос. Очень удобная штука: например через QString/arg никак не засунешь в запрос BLOB-ы, а бинд хавает все, ибо использует QVariant.
Записан
SABROG
Гость
« Ответ #23 : Май 30, 2007, 16:26 »

Т.е., в принципе, это никак не повлияет на скорость заполнения таблицы ?
Записан
goer
Гость
« Ответ #24 : Май 30, 2007, 16:46 »

На скорость заполнения будет влиять время бинда(локальные затраты процесса) и время выполнения запроса(локальные затраты процесса + скорость работы сиквеля)
Записан
SABROG
Гость
« Ответ #25 : Май 30, 2007, 17:03 »

Врятли бинд быстрее операции конкатенации Улыбающийся
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #26 : Май 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 раз Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Вудруф
Гость
« Ответ #27 : Май 31, 2007, 07:45 »

Для Oracle использование связывания может прилично ускорить выполнение запроса, т.к. оптимизируется он один раз, а выполняется - много. Но SQLite - база лёгкая...

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

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

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

Не факт. В хорошем случае запрос и параметры передаются отдельно. Скажем, так делает Pear :: DB, но как это сделано в Qt - смотреть надо.
Записан
SABROG
Гость
« Ответ #28 : Май 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 мс.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #29 : Май 31, 2007, 12:45 »

в даном примере разницы не будет вообще.
это те же самые операции.
когда они записаны подряд одной строкой - они все равно вызываются по очереди.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: 1 [2] 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.118 секунд. Запросов: 23.