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

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

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Работа с контейнерами - терзают сомненья  (Прочитано 13695 раз)
BRE
Гость
« Ответ #15 : Январь 22, 2010, 22:25 »

тоесть  моя функция, если б она была членом класса была бы такая
Код:
const QVector<int>& getValue();
Так ты возвращаешь ссылку на локальный объект, который разрушиться при выходе из функции.
Для Qt-контейнеров, та функция, которую ты привел в первом посте, абсолютно корректная. Никакого копирования данных происходить не будет.
Лучше посмотреть самому, как реализованы контейнеры в Qt.
Записан
vanessa
Гость
« Ответ #16 : Январь 22, 2010, 22:40 »

я вообще-то  имел ввиду примерно следующее
Код:
class blabla
{
public:
const QVector<int>& getValue()
{
return Value;
}

private:
QVector<int> Value;
}
если не углубятся в особенности реализации контейнеров Qt то пока будет существовать экземпляр подобного класса его функция getValue(); будет возвращать не сами данные а ссылку на них ?
Записан
BRE
Гость
« Ответ #17 : Январь 22, 2010, 22:52 »

если не углубятся в особенности реализации контейнеров Qt то пока будет существовать экземпляр подобного класса его функция getValue(); будет возвращать не сами данные а ссылку на них ?
Для подобных случаев лучше возвращать константную ссылку.
Но, на самом деле, для Qt-контейнеров это не так важно. Если возвращать по значению, то копирования самих данных все равно происходить не будет.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Январь 23, 2010, 21:14 »

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

Код:
struct Test {
 double a, b, c, d;
 char data[256];
};
QVector <Test> vec;
vec.resize(10);
Test t1 = vec[0];  //  (a, b, c, d, data) будут скопированы

Др. пример
Код:
struct Test {
 double a, b, c, d;
};
QVector <QString> vec;
vec.push_back("text");
QString s1 = vec[0]; 
Да, действительно, сама строка "text" копироваться не будет (пока s1 не изменена), не будет и выделения памяти при присваивании. Не будет и освобождения в деструкторе. Но ведь QString еще много чего имеет кроме самих данных ("text") - и все эти члены класса будут скопированы в s1. А это ну никак не скорость возврата по указателю/ссылке.

Ну и конечно, все это только до первой модификации s1.
Код:
s1 += "a";
И получаем все прелести копирования по значению - по полной программе.
Записан
BRE
Гость
« Ответ #19 : Январь 23, 2010, 21:32 »

Давайте на примерах
Давай.
Речь идет о издержках при возвращении Qt-контейнеров по значению, т.е.:
Код
C++ (Qt)
struct Test
{
...
};
 
QVector<Test> buildVector()
{
QVector<Test> vec;
// Заполняем вектор
return vec;
}
 
void func()
{
QVector<Test> v = buildVector();
}
 

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

Вспомним, что вектор хранит данные в непрерывном блоке и может сообщить нам адрес его первого элемента.
Тогда меняем код и смотри:

Код
C++ (Qt)
struct Test
{
...
};
 
QVector<Test> buildVector()
{
QVector<Test> vec;
// Заполняем вектор
qDebug() << vec.data() << vec.size();
return vec;
}
 
void func()
{
QVector<Test> v = buildVector();
qDebug() << vec.data() << vec.size();
}
 

Что же мы видим? И в первом и во втором отладочном выводе адреса реального расположения данных не изменились, как лежали они в одном месте, там и лежат. Чудеса.  Шокированный
А что же произошло на самом деле? А с этим нужно разобраться самому...
Еще удивительным может показаться вывод следующей команды:

Код
C++ (Qt)
QVector<Test> vec;
qDebug << sizeof( vec );
 
Это к тем издержкам равным передаче ссылки/указателя...
« Последнее редактирование: Январь 23, 2010, 21:34 от BRE » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Январь 24, 2010, 00:19 »

Код
C++ (Qt)
struct Test
{
...
};
 
QVector<Test> buildVector()
{
QVector<Test> vec;
// Заполняем вектор
return vec;
}
 
void func()
{
QVector<Test> v = buildVector();
}
 

Я утверждаю, что в этом коде не будут копироваться данные находящиеся в векторе и издержки при таком использовании будут такими же, как и при использовании ссылок (или указателей).
Я полностью согласен с Вашим утверждением, но это не имеет никакого отношения к Qt контейнерам, ни к Qt вообще. Все то же самое будет работать с std::vector или просто с любым классом (даже и не контейнером). Как объяснил Rcus такая оптимизация встроена практически во все современные компиляторы. Для строки

Код:
QVector<Test> v = buildVector();
выполнится один конструктор и ни одного деструктора QVector. Однако нет никаких оснований обобщать этот частный случай. Напр. попробуем присвоить еще раз

Цитировать
...
v = buildVector();
И "увы" - мы имеем вызванный деструктор (для возвращенного объекта) + оператор присваивания, который примерно = конструктор + деструктор
Записан
BRE
Гость
« Ответ #21 : Январь 24, 2010, 00:26 »

Я полностью согласен с Вашим утверждением, но это не имеет никакого отношения к Qt контейнерам, ни к Qt вообще. Все то же самое будет работать с std::vector или просто с любым классом (даже и не контейнером). Как объяснил Rcus такая оптимизация встроена практически во все современные компиляторы.
Это имеет прямое отношение к Qt-контейнерам. Можно сделать еще двадцать присвоений и для всех векторов будет одна копия данных.
Это легко проверяется с помощью вызова метода: vec.isDetached(), который сообщает, эксклюзивно или нет используются данные. А использует он для этого атомарную переменную ref, содержащую число объектов QVector, которые разделяю данные.
Стоит все таки заглянуть в исходники Qt.

Насчет того-же самого с std::vector...
Не умеет std::vector такого, не умеет... Поэтому, я и написал о том, что Тролли вначале поработали, а теперь могут использовать...
Код
C++ (Qt)
#include <QApplication>          
#include <QVector>              
#include <vector>                
#include <QDebug>                
 
QVector<int> buildVector()
{                        
       QVector<int> vec;
       for( int i = 0; i < 100; ++i )
               vec.append( i );
 
       qDebug() << vec.constData() << vec.size();
       return vec;
}
 
std::vector<int> buildVector_std()
{
       std::vector<int> vec;
       for( int i = 0; i < 100; ++i )
               vec.push_back( i );
 
       qDebug() << &vec[ 0 ] << vec.size();
       return vec;
}
 
int main( int /*argc*/, char */*argv*/[] )
{
       QVector<int> vec = buildVector();
       qDebug() << vec.constData() << vec.size();
       QVector<int> vec_new = vec;
       qDebug() << vec_new.constData() << vec_new.size();
 
       qDebug() << "-------------------------------------------------";
 
       std::vector<int> vec1 = buildVector_std();
       qDebug() << &vec1[ 0 ] << vec1.size();
       std::vector<int> vec1_new = vec1;
       qDebug() << &vec1_new[ 0 ] << vec1_new.size();
 
       return 0;
}
 
Цитировать
0xc44fa0 100
0xc44fa0 100
0xc44fa0 100
-------------------------------------------------
0xc46cc0 100
0xc46cc0 100
0xc46ed0 100


И "увы" - мы имеем вызванный деструктор (для возвращенного объекта) + оператор присваивания, который примерно = конструктор + деструктор
А я и не говорил, что не будет вызван деструктор для локального объекта. Он вызовется, также как и оператор присваивания, только данные копироваться не будут. Скопируется только указатель на внутренний shared-объект.

Код
C++ (Qt)
inline ~QVector() { if (!d) return; if (!d->ref.deref()) free(p); }
А если вызов деструктора, который не делает никаких тяжелых операций, считать большими издержками, то для чего использовать C++?
На счет такой "оптимизации" я выше уже высказался.
« Последнее редактирование: Январь 24, 2010, 01:06 от BRE » Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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