2016-02-01 4 views
1

Я хочу, чтобы создать карту устройств таким образом, что карта содержит:QMap вставить QVector <QString> указателем или значением?

QString «DeviceID» и QVector «список команд»

В настоящее время у меня есть QMap следующим образом:

QMap<QString, QVector<QString> *> devices; 

QVector<QString> *pCommands= new QVector<QString>; 
//  : 
// Fill pCommands with lots of data here 
//  : 
devices.insert(RadioID, pCommands); 

Но мне интересно, если это на самом деле лучше тогда:

QMap<QString, QVector<QString>> devices; 

QVector<QString> commands; 
//  : 
// Fill commands with lots of data here 
//  : 
devices.insert(RadioID, commands); 

Я уверен, что я где-то читал, что Qt делает что-то весьма эффективным при копирование данных. Я не вижу много людей, использующих указатели с Qt, и кажется бесполезным, что я должен пройти QMap, удалив все QVector в конце ...

Я использую C++ 11, поэтому, возможно, какой-то шаг семантика может работать здесь?

EDIT Я изменил комментарии в коде, чтобы показать, что вектор не пуст. Также я бы сказал, что мне не нужно менять данные после их сохранения.

+2

Если у вас нет конкретной причины использовать указатели, я бы избегал их. – NathanOliver

+0

@NathanOliver Пытается сэкономить память:) –

+1

Вы собираетесь использовать память независимо от того, используете ли вы ее. Если вы собираетесь «делиться» ими, вы должны посмотреть на общий указатель, который будет управлять указателем. – NathanOliver

ответ

4

Нет причин считать вручную выделение векторов лучше.

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

Я использую C++ 11, поэтому, возможно, здесь может работать какой-то семантический сдвиг?

Если QMap::insert поддерживает движение семантики, и если QVector этого движения-построимый как их стандартные библиотеки коллег, то вы могли бы действительно переместить вектор в карту. Но перемещение пустого вектора происходит так же быстро, как и копирование.

Если QMap имеет функцию emplace, как функция std::map, то вы можете даже построить вектор на месте, даже не двигаясь.

Я не знаком с Qt, хотя вам нужно будет проверить эти детали из документации. Независимо от того, поддерживает ли Qt семантику перемещения, не меняется тот факт, что ручное управление памятью является болью.


Edit: в соответствии с documentationQVector, как представляется, быть подвижным, но QMap не поддерживает перемещение семантики. Однако, как указывает Арпегий и документация, QVector делает оптимизацию при копировании на запись, поэтому пока скопированный вектор не будет изменен, данные не будут скопированы. Ничего из этого не имеет значения, при копировании пустого вектора.


Edit снова

Если добавленные векторы полны данных, то копирование действительно довольно дорого, если он не остается неизменным. Перемещение будет исправлено, но QMap, похоже, не поддерживает это.Однако есть еще один трюк: вставьте пустой вектор, а затем swap полный вектор с пустым на карте.

+0

@code_fodder Ufortunatly 'QMap :: insert' не использует семантику перемещения, но как http://doc.qt.io/qt-5/qvector.html#QVector-3 ее избегает копирования всего QVector, поэтому переход семантика здесь не нужна. – Arpegius

+0

@ Арпеджий хорошо, перемещение семантики все равно будет необходимо, когда скопированный вектор нужно изменить - это то, что я бы предположил, что нужно выполнить код_fodder, потому что это вызовет копирование данных. Но нет необходимости в перемещении или COW, если вы копируете пустой вектор, такой как code_fodder делает :) – user2079303

+0

Правильно, я не предполагал, что он всегда вставляет пустой вектор. – Arpegius

1

Самый простой и довольно много идиоматических способ сделать это будет:

QMap<QString, QVector<QString>> devices; 

// Get the vector constructed in the map itself. 
auto & commands = devices[RadioID]; 
// Fill commands with lots of data here - a bit faster 
commands.resize(2); 
commands[0] = "Foo"; 
commands[1] = "Bar"; 
// Fill commands with lots of data here - a bit slower 
commands.append("Baz"); 
commands.append("Fan"); 

Вы увидите эту модель часто в Qt и другой код, и это самый простой способ сделать это, что одинаково хорошо работает на C++ 98 и C++ 11 :)

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

+0

Спасибо за то, что Kuba (+1), если я правильно помню, подсчет счетчика ссылок - это специфическое поведение Qt, поэтому это решение специфично в контейнеры Qt (т. е. не работает также для C++ STL)? –

+0

@code_fodder Единственная разница в производительности здесь будет заключаться между 'QString' и' std :: string'. «Команды» - это ссылка на вектор, уже на карте. Вы можете использовать 'std :: map >', и он будет работать точно так же, как и выше. Если вы не хотите копировать строки, используйте 'emplace_back' вместо' append'. –

+0

Можем ли мы быть уверены, что изменения на карте не приведут к аннулированию ссылки? – Thomas