Pimpl copying

Peter Kümmel syntheticpp at gmx.net
Fri Jul 14 15:42:09 BST 2006


Peter Kümmel wrote:
> The problem is that KTempDirTest uses the Pimpl idiom, but does
> not define a copy ctor/operator, so all private data gets lost
> on copying, nor does it forbid copying.
> 
> I fear kdelibs is full of this bug and think we should catch
> such constructs at compile time.
> 
> Shouldn't we introduce a coding policy something like this:

I've solved the issue by this patch:

SVN commit 562284 by kuemmel:

macro for pimpl handling:
 * consistent naming of the private implementation
 * explicit copying, checked by the linker
 * disable copying, checked at compile time
 * const pimpl


 M  +1 -0      TODO
 M  +2 -2      kdecore/ktempdir.cpp
 M  +1 -2      kdecore/ktempdir.h
 M  +2 -2      kdecore/tests/ktempdirtest.cpp
 M  +62 -0     kdemacros.h.cmake


--- trunk/KDE/kdelibs/TODO #562283:562284
@@ -10,6 +10,7 @@
   help prevent mistakes where developers forget to delete the pointer. Maybe
make use of
   Qt4 helper macros?
   (Frerich)
+  Use KDE_PIMPL_EN(DIS)ABLE_COPY to avoid compiler generated copy functions (Kümmel)

 - Move all utility functions away from KApplication. TBD: Make KApplication
   a very thin wrapper around QApplication. Ideally, KApplication should go
--- trunk/KDE/kdelibs/kdecore/ktempdir.cpp #562283:562284
@@ -53,7 +53,7 @@
 #include <kdebug.h>
 #include "kde_file.h"

-class KTempDir::Private
+class KTempDir::KTempDirPrivate
 {
 public:
    int _error;
@@ -66,7 +66,7 @@
 #define bAutoDelete d->_autoDelete
 };

-KTempDir::KTempDir(QString directoryPrefix, int mode) : d(new Private)
+KTempDir::KTempDir(QString directoryPrefix, int mode) : d(new KTempDirPrivate)
 {
    bAutoDelete = false;
    bExists = false;
--- trunk/KDE/kdelibs/kdecore/ktempdir.h #562283:562284
@@ -161,8 +161,7 @@
    void setError(int error);

 private:
-   class Private;
-   Private *const d;
+   KDE_PIMPL_DISABLE_COPY(KTempDir);
 };

 #endif
--- trunk/KDE/kdelibs/kdecore/tests/ktempdirtest.cpp #562283:562284
@@ -26,7 +26,7 @@

 void KTempDirTest::testBasic()
 {
-	KTempDir dir = KTempDir("test");
+	KTempDir dir("test");
 	QVERIFY(dir.status() == 0);
 	QVERIFY(dir.exists());
 	QVERIFY(QDir(dir.name()).exists());
@@ -51,7 +51,7 @@

 void KTempDirTest::testCreateSubDir()
 {
-	KTempDir dir = KTempDir("test");
+	KTempDir dir("test");
 	dir.setAutoDelete(true);
 	QVERIFY(dir.status() == 0);
 	QVERIFY(dir.exists());
--- trunk/KDE/kdelibs/kdemacros.h.cmake #562283:562284
@@ -361,4 +361,66 @@
 # define KDE_DUMMY_QHASH_FUNCTION(C)
 #endif

+/**
+ * @def KDE_PIMPL_ENABLE_COPY
+ *
+ * KDE_PIMPL_ENABLE_COPY is a macro for the
+ * consistent Pimpl (Pointer to Implementation) usage.
+ *
+ * It ensures that the code shows explicit how
+ * assignment and copying is handled.
+ *
+ * Using KDE_PIMPL_ENABLE_COPY one must also implement
+ * the copy constructor and the assignment operator.
+ *
+ * Using KDE_PIMPL_DISABLE_COPY makes the class NOT copyable
+ * by declaring the related functions as private.
+ *
+ * Example:
+ *
+ * \code
+ * class KClass {
+ * public:
+ *     KClass();
+ *     ~KClass();
+ * private:
+ *     KDE_PIMPL_ENABLE_COPY(KClass);
+ * };
+ *
+ * class KClass::KClassPrivate {
+ * public:
+ *     int data;
+ * };
+ *
+ * KClass::KClass() : d(new KClassPrivate) {}
+ * KClass::~KClass() { delete d; }
+ * KClass::KClass(const KClass& rhs) : d(new KClassPrivate) { operator=(rhs);}
+ * KClass& KClass::operator=(const KClass& rhs) {
+ *   if(this!=&rhs)
+ *       d->data = rhs.d->data;
+ *   return *this;
+ * }
+ * \endcode
+ *
+ */
+
+ /**
+ * @def KDE_PIMPL_DISABLE_COPY
+ *
+ * see:
+ * @sa KDE_PIMPL_ENABLE_COPY
+ */
+
+#define KDE_PIMPL_BASE_MACRO(COPY_ACCESS,X) \
+COPY_ACCESS: \
+    X(const X##&); \
+    X##& operator=(const X##&); \
+private: \
+    class X##Private; \
+    X##Private * const d;
+
+#define KDE_PIMPL_ENABLE_COPY(X)  KDE_PIMPL_BASE_MACRO(public, X)
+#define KDE_PIMPL_DISABLE_COPY(X) KDE_PIMPL_BASE_MACRO(private,X)
+
+
 #endif /* _KDE_MACROS_H_ */




More information about the kde-core-devel mailing list