PDA

View Full Version : QSharedDataPointer compile problem (invalid use of incomplete type)



darkadept
19th January 2010, 23:18
I'm trying to write a very simple program that makes use of QSharedDataPointer and QSharedData.

Here is my class:


#ifndef BUILDING_H
#define BUILDING_H

#include <QSharedData>
#include <QSharedDataPointer>

class BuildingPrivate;

class Building
{
public:
Building();
~Building();

int value() const;
void setValue(int value);

private:
QSharedDataPointer<BuildingPrivate> d;
};

#endif // BUILDING_H



#include "building.h"

class BuildingPrivate : public QSharedData {
public:
BuildingPrivate() {
value = 0;
}
BuildingPrivate(const BuildingPrivate &other) {
value = other.value;
}
~BuildingPrivate() {}

int value;
};

Building::Building()
: d(new BuildingPrivate)
{
}

Building::~Building() { }

int Building::value() const
{
return d->value;
}

void Building::setValue(int value)
{
d->value = value;
}


And here is my main.cpp:


#include <QtCore/QCoreApplication>
#include <QDebug>

#include "myobject.h"

Building build() {
Building test;
test.setValue(888);
return test;
}

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

qDebug() << build().value();

return 0;
}


When I try to compile that I get:


In file included from /usr/include/qt4/QtCore/QSharedData:2,
from building.h:5,
from myobject.h:6,
from main.cpp:5:
/usr/include/qt4/QtCore/qshareddata.h: In copy constructor ‘QSharedDataPointer<T>::QSharedDataPointer(const QSharedDataPointer<T>&) [with T = BuildingPrivate]’:
building.h:10: instantiated from here
/usr/include/qt4/QtCore/qshareddata.h:90: error: invalid use of incomplete type ‘struct BuildingPrivate’
building.h:7: error: forward declaration of ‘struct BuildingPrivate’
/usr/include/qt4/QtCore/qshareddata.h: In destructor ‘QSharedDataPointer<T>::~QSharedDataPointer() [with T = BuildingPrivate]’:
building.h:10: instantiated from here
/usr/include/qt4/QtCore/qshareddata.h:87: error: invalid use of incomplete type ‘struct BuildingPrivate’
building.h:7: error: forward declaration of ‘struct BuildingPrivate’
/usr/include/qt4/QtCore/qshareddata.h:87: warning: possible problem detected in invocation of delete operator:
/usr/include/qt4/QtCore/qshareddata.h:87: warning: invalid use of incomplete type ‘struct BuildingPrivate’
building.h:7: warning: forward declaration of ‘struct BuildingPrivate’
/usr/include/qt4/QtCore/qshareddata.h:87: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
make: *** [main.o] Error 1



What am I missing?

psih128
20th January 2010, 04:39
This member declaration:

QSharedDataPointer<BuildingPrivate> d;Supposes a complete definition of BuildingPrivate - forward declaration wont work. Just move the definition of the BuildingPrivate to the header

darkadept
20th January 2010, 04:50
Ahh ok I understand that now.

But doesn't that kind of defeat the purpose of having a private implementation class? Plus the Qt documentation for QSharedDataPointer says the forward declaring is good enough. Any ideas?

darkadept
20th January 2010, 04:51
(sorry double posted)

wysota
20th January 2010, 11:58
You need to have a copy constructor for the public class.


Building(const Building &other) : d(other.d) {}

darkadept
20th January 2010, 16:34
Yes you do! Thank you! I'm kicking myself now for not thinking about this problem properly. ;-)

Also, remember to implement all the operators you might need, such as operator== or operator< etc.

Here is my better and functioning Building class. IMHO this is a good template if you want to make a custom value class like QString that uses implicit sharing. In fact, go look at the QString source file to gain insight in building a good value class.



#ifndef BUILDING_H
#define BUILDING_H

#include <QSharedDataPointer>
class BuildingPrivate;

class Building
{
public:
Building(); //Constructor
Building(const Building &other); //Copy-constructor
~Building(); //Destructor

Building &operator=(const Building &rhs); //Assignment operator
bool operator==(const Building &other) const; //Equality operator
inline bool operator!=(const Building &other) const { return !operator==(other); } //Inequality operator (efficiently reuses your equality operator)

//Your getters and setters
int value() const;
void setValue(int value);

private:
QSharedDataPointer<BuildingPrivate> d;
};

#endif // BUILDING_H




#include "building.h"

#include <QSharedData>

class BuildingPrivate : public QSharedData {
public:
BuildingPrivate() {
value = 0;
}
BuildingPrivate(const BuildingPrivate &other)
: QSharedData(other) {
value = other.value;
}
~BuildingPrivate() { }

int value;
};

Building::Building()
: d(new BuildingPrivate)
{ }

Building::Building(const Building &other)
: d(other.d)
{ }

Building::~Building()
{ }

Building &Building::operator=(const Building &rhs)
{
if (this==&rhs) return *this; //Protect against self-assignment
d = rhs.d;
return *this;
}

bool Building::operator==(const Building &other) const
{
/* If your value class has many data members you can get clever
and compare the fastest values first (like comparing integers) and
then move on to more cpu intensive compares. */

if (d->value == other.d->value)
return true;
return false;
}

int Building::value() const
{
return d->value;
}

void Building::setValue(int value)
{
d->value = value;
}

wysota
20th January 2010, 19:58
I'm kicking myself now for not thinking about this problem properly. ;-)

It's right there in the docs, you know... Right after the sentence stating that forward declaration is enough ;)

tangential
5th February 2010, 02:05
You need to have a copy constructor for the public class.


Building(const Building &other) : d(other.d) {}

Is this in a FAQ somewhere? I work for QTDF, and even I've been caught by this one :)

Gh0str1d3r
29th August 2010, 13:40
Hi,

I get the same compilation error with my classes, even though I have implemented the copy constructor. Here is the compiler output:


[ 16%] Building CXX object CMakeFiles/test2.dir/AbstractInteractiveQGraphicsItem.cpp.o
[ 33%] Building CXX object CMakeFiles/test2.dir/InteractiveQGraphicsLineItemData.cpp.o
[ 50%] Building CXX object CMakeFiles/test2.dir/InteractiveQGraphicsLineItem.cpp.o
[ 66%] Building CXX object CMakeFiles/test2.dir/main.cpp.o
In file included from /usr/include/qt4/QtCore/QSharedData:1,
from InteractiveQGraphicsLineItem.h:23,
from main.cpp:2:
/usr/include/qt4/QtCore/qshareddata.h: In copy constructor 'QSharedDataPointer<T>::QSharedDataPointer(const QSharedDataPointer<T>&) [with T = InteractiveQGraphicsLineItemData]':
InteractiveQGraphicsLineItem.h:44: instantiated from here
/usr/include/qt4/QtCore/qshareddata.h:93: error: invalid use of incomplete type 'struct InteractiveQGraphicsLineItemData'
InteractiveQGraphicsLineItem.h:38: error: forward declaration of 'struct InteractiveQGraphicsLineItemData'
/usr/include/qt4/QtCore/qshareddata.h: In destructor 'QSharedDataPointer<T>::~QSharedDataPointer() [with T = InteractiveQGraphicsLineItemData]':
InteractiveQGraphicsLineItem.h:44: instantiated from here
/usr/include/qt4/QtCore/qshareddata.h:90: error: invalid use of incomplete type 'struct InteractiveQGraphicsLineItemData'
InteractiveQGraphicsLineItem.h:38: error: forward declaration of 'struct InteractiveQGraphicsLineItemData'
/usr/include/qt4/QtCore/qshareddata.h:90: warning: possible problem detected in invocation of delete operator:
/usr/include/qt4/QtCore/qshareddata.h:90: warning: invalid use of incomplete type 'struct InteractiveQGraphicsLineItemData'
InteractiveQGraphicsLineItem.h:38: warning: forward declaration of 'struct InteractiveQGraphicsLineItemData'
/usr/include/qt4/QtCore/qshareddata.h:90: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
make[2]: *** [CMakeFiles/test2.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/test2.dir/all] Error 2
make: *** [all] Error 2

The InteractiveQGraphicsLineItem object is declared as


#ifndef INTERACTIVEQGRAPHICSLINEITEM_H
#define INTERACTIVEQGRAPHICSLINEITEM_H

#include <QSharedData>
#include "AbstractInteractiveQGraphicsItem.h"

class QGraphicsScene;
class QRectF;
class QColor;
class QLineF;
class QPainter;
class QStyleOptionGraphicsItem;
class QWidget;
class QGraphicsSceneHoverEvent;
class QGraphicsSceneMouseEvent;
class QKeyEvent;
class QGraphicsSceneWheelEvent;

class InteractiveQGraphicsLineItemData;

class InteractiveQGraphicsLineItem : public AbstractInteractiveQGraphicsItem
{
public:
InteractiveQGraphicsLineItem(AbstractInteractiveQG raphicsCoordinationItem* parent = 0, QGraphicsScene* scene = 0);
InteractiveQGraphicsLineItem(const InteractiveQGraphicsLineItem & other) : d(other.d) {}
virtual ~InteractiveQGraphicsLineItem() {}

virtual QRectF boundingRect() const;
virtual QLineF getLine();
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
virtual void setDrawNewRectOnClickOutOfTheFrame(bool b);
virtual void setLine(const QLineF& line);
virtual void setLineColor(const QColor &color);
virtual void setHandleFillColor(const QColor &color);
virtual void setHandleFrameColor(const QColor &color);
virtual void setMaximumHandleSize(double size);

protected:
virtual void adjustHandleSize();
virtual void keyPressEvent(QKeyEvent* event);
virtual void keyReleaseEvent(QKeyEvent* event);
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);

virtual void updateHandles();

protected:
QSharedDataPointer<InteractiveQGraphicsLineItemData> d;
};

#endif // INTERACTIVEQGRAPHICSLINEITEM_H

The declaration of the data object looks like


#ifndef INTERACTIVEQGRAPHICSLINEITEMDATA_H
#define INTERACTIVEQGRAPHICSLINEITEMDATA_H

#include <QSharedData>
#include <QRectF>
#include <QLineF>
#include <QPointF>
#include <QVector>
#include <QColor>

class InteractiveQGraphicsLineItemData : public QSharedData
{
public:
InteractiveQGraphicsLineItemData();
InteractiveQGraphicsLineItemData(const InteractiveQGraphicsLineItemData & other) {}
~InteractiveQGraphicsLineItemData() {}
QLineF line;
bool mouseDown;
bool newSelection;
bool drawNewLineOnClickOutOfTheFrame;
double handleSize;
double maximumHandleSize;
QRectF* mouseOverHandle;
QPointF dragStartPoint;
QLineF lineBeforeDrag;
QColor lineColor;
QColor handleFillColor;
QColor handleFrameColor;

QRectF LineHandle1, LineHandle2;

QVector<QRectF*> handles;
};

#endif // INTERACTIVEQGRAPHICSLINEITEMDATA_H

and the main.cpp


#include <QCoreApplication>
#include "InteractiveQGraphicsLineItem.h"


int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
InteractiveQGraphicsLineItem foo;
return app.exec();
}


I think this is all the relevant information. Strange enough, I have a almost identical class which defines a Rect instead of a Line, and that class compiles fine even without any copy constructor. Can anyone help me?

Gh0str1d3r
29th August 2010, 15:30
for completeness, here is the InteractiveQGraphicsFrameItem class, which works without problems:


#ifndef INTERACTIVEQGRAPHICSFRAMEITEM_H
#define INTERACTIVEQGRAPHICSFRAMEITEM_H

#include <QSharedData>
#include "GraphicItemsSharedLibrary.h"
#include "AbstractInteractiveQGraphicsItem.h"

class QGraphicsScene;
class QRectF;
class QColor;
class QPainter;
class QStyleOptionGraphicsItem;
class QWidget;
class QGraphicsSceneHoverEvent;
class QGraphicsSceneMouseEvent;
class QKeyEvent;
class QGraphicsSceneWheelEvent;

class InteractiveQGraphicsFrameItemData;

class GRAPHICITEMS_SHAREDLIB_LIB_EXPORT InteractiveQGraphicsFrameItem : public AbstractInteractiveQGraphicsItem
{
public:
InteractiveQGraphicsFrameItem(AbstractInteractiveQ GraphicsCoordinationItem* parent = 0, QGraphicsScene* scene = 0);
virtual ~InteractiveQGraphicsFrameItem();
virtual QRectF boundingRect() const;
virtual QRectF getRect();
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
virtual void setDrawNewRectOnClickOutOfTheFrame(bool b);
virtual void setFillColor(const QColor &color);
virtual void setFrame(const QRectF& rect);
virtual void setFrameColor(const QColor &color);
virtual void setHandleFillColor(const QColor &color);
virtual void setHandleFrameColor(const QColor &color);
virtual void setMaximumHandleSize(double size);
virtual void setOuterFillColor(const QColor &color);

protected:
virtual void adjustHandleSize();
virtual void keyPressEvent(QKeyEvent* event);
virtual void keyReleaseEvent(QKeyEvent* event);
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);
// virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event);
// virtual void wheelEvent(QGraphicsSceneWheelEvent* event);

virtual void updateHandles();

protected:
QSharedDataPointer<InteractiveQGraphicsFrameItemData> d;
};

#endif // INTERACTIVEQGRAPHICSFRAMEITEM_H



#ifndef INTERACTIVEQGRAPHICSFRAMEITEMDATA_H
#define INTERACTIVEQGRAPHICSFRAMEITEMDATA_H

#include <QSharedData>
#include <QRectF>
#include <QPointF>
#include <QVector>
#include <QColor>

class InteractiveQGraphicsFrameItemData : public QSharedData
{
public:
InteractiveQGraphicsFrameItemData();

QRectF frame;
bool mouseDown;
bool mouseInObject;
bool newSelection;
bool lockAspectRatio;
bool drawNewRectOnClickOutOfTheFrame;
double handleSize;
double maximumHandleSize;
QRectF* mouseOverHandle;
QPointF dragStartPoint;
QRectF frameBeforeDrag;
QColor fillColor;
QColor frameColor;
QColor handleFillColor;
QColor handleFrameColor;
QColor outerFillColor;

// naming convention for handles
// T top, B bottom, R Right, L left
// 2 letters: a corner
// 1 letter: the handle on the middle of the corresponding side
QRectF TLHandle, TRHandle, BLHandle, BRHandle;
QRectF LHandle, THandle, RHandle, BHandle;

QVector<QRectF*> handles;
};

#endif // INTERACTIVEQGRAPHICSFRAMEITEMDATA_H

Now where is the difference to the InteractiveQGraphicsLineItem class, which makes the one compile and the other not?