Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a deep copy of a QList (Qt 4.8)

Tags:

c++

qt

I'm trying to make a deep copy of a QList, I'm using Qt 4.8. In the code below mData is a QList<unsigned char> member variable of the Test class.

In first instance I thought the code below should work, however diving deeper in Qt's implicitly shared (i.e. copy-on-write) concept, I'm doubting if this is the correct way to go.

Test::Test(QList<unsigned char> &aData) {
    mData.QList(aData);
}

According Qt,

QList::QList(const QList & other)

Constructs a copy of other.

This operation takes constant time, because QList is implicitly shared. This makes returning a QList from a function very fast. If a shared instance is modified, it will be copied (copy-on-write), and that takes linear time.

I want to ensure that if aData goes out of scope or if the content of aData is modified, this doesn't change the content of mData. Is this possible without having to iterate and copy each list entry separately?

Note: this is not a duplicate of Qt 4.5 - QList::QList(const QList&) - is this a deep copy constructor? because this question implicitly asks how to create a deep copy" instead of if something is a deep copy.

like image 209
Gio Avatar asked May 18 '15 15:05

Gio


1 Answers

The implicit copy mechanism of Qt will automatically create a deep copy of a QList if this is required.

QList<int> a;
a.append(1);
a.append(2);

Now we have a list a with two values.

QList<int> b = a;
// a = 1, 2
// b = 1, 2

The copy of b is the same as a. The two list share the same data, so the copy operation needs almost no time, but b is marked internally as a copy.

b.append(3);
// a = 1, 2
// b = 1, 2, 3

Another example:

QList<int> a;
a << 1 << 2 << 3;
// a = 1, 2, 3
QList<int> b = a;
// a = 1, 2, 3; b = 1, 2, 3
b[0] = 7;
// a = 1, 2, 3; b = 7, 2, 3

As soon you change something on b, an implicit deep copy is made. It does not matter how the copied list is modified, it works on any method.

If you are using references, there is no deep copy made automatically:

void addElement(QList<int> &x, int e) {
    x.append(e);
}

QList<int> a;
a.append(1);
a.append(2);
addElement(a, 3);
// a = 1, 2, 3

To enforce a deep-copy, just make a copy of the list inside of the function. But of course, better just pass the argument as copy instead as reference, this simplifies the code.

void printListPlus1(QList<int> &x) {
    QList<int> xCopy = x; 
    xCopy.append(1);
    // print the list
}

QList<int> a;
a << 1 << 2;
// a = 1, 2
printListPlus1(a);
// a = 1, 2

So actually, you can use a QList and any other Qt container similar to a primitive data type like int or like QString. The implicit copy is automatically done in the "background".

Your Example

So your example should just use a simple copy:

class Test {
    QList<int> _m;
public:
    Test(QList<int> m) : _m(m) {
    }    
}

The class Test automatically creates a deep-copy of the parameter m. Because of the implicit copy mechanism, use a copy of the parameter m is not much slower than use a reference. The deep copy is automatically done at the first modification of the list.

If you would like to use a reference, use a const reference:

class Test {
    QList<int> _m;
public:
    Test(const QList<int> &m) : _m(m) {
    }    
}

This will create an implicit deep-copy as well.

like image 68
Flovdis Avatar answered Oct 26 '22 23:10

Flovdis