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?
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.