PDA

View Full Version : Converting C++ to Qt4



ComaWhite
10th July 2008, 11:29
Hello. I have this class in pure C++.



#ifndef VALUEVECTOR_HPP_
#define VALUEVECTOR_HPP_

#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using std::vector;
using std::find;
#include "Object.hpp"
#include "ComaPtr.hpp"
#include "Value.hpp"

class ValueVector : public Object {
typedef ComaPtr<Value> type;
public:

ValueVector() {
}

ValueVector(Value* value) {
clearChildren();
addChildren(value);
}

ValueVector(unsigned length) {
clearChildren();
size(length);
}

ValueVector(const ValueVector& rhs) {
*this = rhs;
}

type& operator[](unsigned index) {
return m_children[index];
}

bool operator==(ValueVector& vv) {
if(size() != vv.size()) {
return false;
}

for(unsigned i = 0; i < size(); ++i) {
for(unsigned j = 0; j < vv.size(); ++j) {
if(m_children[i] != vv[i]){
return false;
}
}
}
return true;
}

bool operator!=(ValueVector& vv) {
if(size() != vv.size()) {
return true;
}

for(unsigned i = 0; i < size(); ++i) {
for(unsigned j = 0; j < vv.size(); ++j) {
if(m_children[i] != vv[i]){
return true;
}
}
}
return false;
}

void addChildren(type children) {
assert(find(m_children.begin(), m_children.end(), children) == m_children.end());
m_children.push_back(children);
}

unsigned capacity() const {
return m_children.capacity();
}

void capacity(unsigned length) {
m_children.reserve(length);
}

void clearChildren() {
m_children.clear();
}

void setChildren(unsigned index, type children) {
assert(index < size());
m_children[index] = children;
}

unsigned size() const {
return m_children.size();
}

void size(unsigned length) {
m_children.resize(length);
}
private:
vector<type> m_children;
};

typedef ComaPtr<ValueVector> ValueVectorPtr;

#endif /*VALUEVECTOR_HPP_*/


And I was googling around for like a Smart Pointer in Qt4.4 but I couldn't seem to come up with any answers except for QGuardedPtr<> but only seems to appear in Qt3 which I don't use.

ComaPtr<> is like boost::shared_ptr except my pointer class addRef and release which is all done in ComaPtr<> which only works on classes that inherit from my custom reference counting class Object. And was wondering. how do I set up QVector to hold an array of pointers of Value (example class). And automatically reference count it?

caduel
10th July 2008, 11:58
Did you take a look at QSharedDataPointer?

Also, nothing stops you from using boost::shared_ptr together with Qt...

ComaWhite
10th July 2008, 12:27
Thank you. So one question. I think from reading the doc on it. It will automatically allow a end-user to do like Value* v = new Value(22); and not have to worry about deleting it?

caduel
10th July 2008, 12:54
no, something like that is just about impossible in C++.

The way I read it, it works like boost::shared_ptr.

QSharedDataPointer<Value> v = new Value(22);

You have to assign the 'naked' pointer to a QSharedDataPointer. Once the (last copy of this) QSharedDataPointer goes out of scope the reference count gets zero and the object deleted.
(Note that this is a huge difference to boost::shared_ptr: a QSharedDataPointer "detaches" when you call a non-const op on it (effectifely creating a separate copy).
This is what you want for a value-like class like QString (see below). It might not be at all what you want.)
If you do not want to implement a shared value class, stick to boost::shared_ptr, imo.


The other thing is, that this class was designed for implementing 'value-like' shared objects. Like a QString.
You will hardly ever write

QString *s = new QString;
QString hides this and maybe uses a QSharedDataPointer internally.
The docs illustrated how to do this.
(This is basically a more adavanced form of the pimpl idiom with better support for efficient (and correct) copying of objects.)

HTH

wysota
10th July 2008, 18:11
QSharedDataPointer operates on QSharedData, so this is probably not going to work.

Something like:

SomeTypeVeryWisePointer ptr = new SomeType;
doesn't make much sense if you want the data to be deleted when ptr goes out of scope. If you want that, simply write:

SomeType obj;
When the variable goes out of scope, the compiler will delete it for you.

There is also a chance you want a reference counting pointer:

SharedPtr ptr1 = new SomeType;
SharedPtr ptr2 = ptr1;
delete ptr1; // this is just an example...
ptr2->stillWorking();
In that case QSharedDataPointer (or rather QExplicitelySharedDataPointer) will be helpful if you implement SomeType as a shared class. Then you'll be able to write:

SomeType obj1;
SomeType obj2 = obj1;
And both facade objects will point to the same set of data.

You might also want a guarded pointer (similar to what QMutexLocker does). In that case you can implement it yourself.

template <class T> class GuardedPtr {
public:
GuardedPtr(T *o) { ptr = o; }
~GuardedPtr(){ delete ptr; }
private:
T *ptr;
};

and then use it like this:

xyz *ptr = new xyz;
GuardedPtr<ptr> guard(ptr);
//...
// ptr gets deleted when guard goes out of scope


Just be aware it's a stupid class that may cause much trouble.

ComaWhite
11th July 2008, 00:18
I think I finally got it working. But I thought you would call detach before setting the value and not after?




#include <QExplicitlySharedDataPointer>
#include <QSharedData>
#include <QDebug>

class ValueData : public QSharedData {
public:
ValueData()
: m_value(1) {
}
ValueData(int value)
: m_value(value) {
}
~ValueData() { }
ValueData(const ValueData& v)
: QSharedData(v),
m_value(v.m_value) {
}
void print() {
qDebug() << m_value;
}

int m_value;
};

class ValueT {
public:
ValueT() {
d = new ValueData;
}

ValueT(int value) {
d = new ValueData(value);
}

void setValue(int value) {
d->m_value = value;
d.detach();
}
void print() {
d->print();
}
private:
QExplicitlySharedDataPointer<ValueData> d;
};


But one last question. What happens if the end user does


ValueT* v = new ValueT(123);


Will it cause a a memory leak if s/he doesn't call delete?

keeney
11th July 2008, 01:22
Yes, then you must delete it yourself

ComaWhite
11th July 2008, 07:43
It doesn't like when you create your own operator= or copy constructor. Because I tried to make like 3 of them and when I did. It would never print to console unless I removed them :(

wysota
11th July 2008, 08:33
I think I finally got it working. But I thought you would call detach before setting the value and not after?

With an explicitely shared pointer you should call detach only if you want to separate the two objects (so copy is always a shallow copy by default). If you want to always separate them, use QSharedDataPointer which calls detach itself (copy on write).