Results 1 to 12 of 12

Thread: Segfault while using Pimpl idiom with Qt types.

  1. #1
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Segfault while using Pimpl idiom with Qt types.

    I'm starting to use the Pimpl idiom (aka cheshire cat, d-pointer) but I'm getting segfaults in my destructors under certain conditions. Let me try to explain:

    Qt Code:
    1. //MYCLASS.H
    2.  
    3. class MyClassPrivate;
    4.  
    5. class MyClass {
    6. public:
    7. MyClass();
    8. MyClass(const MyClass &other);
    9. ~MyClass();
    10.  
    11. private:
    12. MyClassPrivate *d;
    13. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //MYCLASS.CPP
    2. #include "myclass.h"
    3. #include <QString>
    4. #include <QMap>
    5.  
    6. class MyClassPrivate {
    7. public:
    8. QString mystring;
    9. QMap<QString, int> mymap;
    10. };
    11.  
    12. MyClass::MyClass()
    13. : d(new MyClassPrivate)
    14. { }
    15.  
    16. MyClass:MyClass(const MyClass &other)
    17. : d(newMyClassPrivate(*other.d))
    18. { }
    19.  
    20. MyClass::~MyClass()
    21. {
    22. delete d;
    23. }
    To copy to clipboard, switch view to plain text mode 

    I have another class, let's call it MyContainerThingy that also uses Pimpl and stores a MyClass value:

    Qt Code:
    1. //MYCONTAINERTHINGY.H
    2.  
    3. class MyContainerThingyPrivate;
    4.  
    5. class MyContainerThingy {
    6. public:
    7. MyContainerThingy();
    8. MyContainerThingy(const MyContainerThingy &other);
    9. ~MyContainerThingy();
    10.  
    11. private:
    12. MyContainerThingyPrivate *d;
    13. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //MYCONTAINERTHINGY.CPP
    2. #include "mycontainerthingy.h"
    3. #include "myclass.h"
    4.  
    5. class MyContainerThingyPrivate {
    6. public:
    7. MyClass myclass;
    8. };
    9.  
    10. MyContainerThingy::MyContainerThingy()
    11. : d(new MyContainerThingyPrivate)
    12. { }
    13.  
    14. MyContainerThingy:MyContainerThingy(const MyContainerThingy &other)
    15. : d(newMyContainerThingyPrivate(*other.d))
    16. { }
    17.  
    18. MyContainerThingy::~MyContainerThingy()
    19. {
    20. delete d;
    21. }
    To copy to clipboard, switch view to plain text mode 

    These two classes are compiled into a shared library. When I attempt to use these classes from my application it segfaults with the following frame stack (from KDevelop3 debugging via gdb):

    Qt Code:
    1. #0 QBasicAtomicInt::deref
    2. #1 ~QMap
    3. #2 ~MyClassPrivate
    4. #3 ~MyClass
    5. #4 ~MyContainerThingy
    6. #5 ~MyContainer
    7. #6 main
    To copy to clipboard, switch view to plain text mode 

    And it's not only QMap, but QHash, QString as well.

    Any ideas?

  2. #2
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Of course it will crash.

    MyClass contains a pointer to MyClassPrivate, but your MyContainerThingyPrivate's default ctor performs a shallow copy. You need to provide a deep copy ctor.

    You can use QSharedData to take care of the ref count for you...

  3. #3
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Ahhh. ok makes sense in the brain, now let's see what happens in implementation. I'll go try it right away. thanks

  4. #4
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Umm, should I be inheriting QSharedDataPointer for MyClass and MyContainerThingy as well or just inheriting QSharedData for my private classes?


    EDIT: Nevermind. I should read the documentation before I blurt things out.
    Last edited by darkadept; 12th June 2009 at 17:13.

  5. #5
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Segfault while using Pimpl idiom with Qt types.

    It appears you want to use QExplicitlySharedDataPointer, which will call detach automatically when the data object is modified. But it depends on your needs...

    QVector uses QSharedDataPointer...

    EDIT: Error, I mean to say QExplicitlySharedDataPointer does NOT call detach automatically

  6. #6
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Here is my updated code using QExplicitlySharedDataPointers:

    Qt Code:
    1. //MYCLASS.H
    2.  
    3. class MyClassPrivate;
    4.  
    5. class MyClass {
    6. public:
    7. MyClass();
    8. MyClass(const MyClass &other);
    9. ~MyClass();
    10.  
    11. private:
    12. QExplicitlySharedDataPointer<MyClassPrivate> d;
    13. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //MYCLASS.CPP
    2. #include "myclass.h"
    3. #include <QString>
    4. #include <QMap>
    5.  
    6. class MyClassPrivate : public QSharedData {
    7. public:
    8. MyClassPrivate() { }
    9. MyClassPrivate(const MyClassPrivate &other) : QSharedData(other), mystring(other.mystring), mymap(other.mymap) { }
    10. QString mystring;
    11. QMap<QString, int> mymap;
    12. };
    13.  
    14. MyClass::MyClass()
    15. : d(new MyClassPrivate)
    16. { }
    17.  
    18. MyClass::MyClass(const MyClass &other)
    19. : d(other.d)
    20. { }
    21.  
    22. MyClass::~MyClass()
    23. { }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //MYCONTAINERTHINGY.H
    2.  
    3. class MyContainerThingyPrivate;
    4.  
    5. class MyContainerThingy {
    6. public:
    7. MyContainerThingy(const MyClass &cls);
    8. MyContainerThingy(const MyContainerThingy &other);
    9. ~MyContainerThingy();
    10.  
    11. private:
    12. QExplicitlySharedDataPointer<MyContainerThingyPrivate> d;
    13. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //MYCONTAINERTHINGY.CPP
    2. #include "mycontainerthingy.h"
    3. #include "myclass.h"
    4.  
    5. class MyContainerThingyPrivate : public QSharedData {
    6. public:
    7. MyContainerThingyPrivate() { }
    8. MyContainerThingyPrivate(const MyContainerThingyPrivate &other) : QSharedData(other), myclass(other.myclass) { }
    9. MyClass myclass;
    10. };
    11.  
    12. MyContainerThingy::MyContainerThingy(const MyClass &cls)
    13. : d(new MyContainerThingyPrivate)
    14. {
    15. d->myclass = cls;
    16. }
    17.  
    18. MyContainerThingy::MyContainerThingy(const MyContainerThingy &other)
    19. : d(other.d)
    20. { }
    21.  
    22. MyContainerThingy::~MyContainerThingy()
    23. {
    24. }
    To copy to clipboard, switch view to plain text mode 

    I'm getting a compile time error:

    Qt Code:
    1. compiling myclass.cpp (g++)
    2. compiling mycontainerthingy.cpp (g++)
    3. myclass.h:27: instantiated from here
    4. /usr/include/qt4/QtCore/qshareddata.h:169: error: invalid use of incomplete type 'struct MyClassPrivate'
    5. myclass.h:25: error: forward declaration of 'struct MyClassPrivate'
    6. /usr/include/qt4/QtCore/qshareddata.h:170: error: invalid use of incomplete type 'struct MyClassPrivate'
    7. myclass.h:25: error: forward declaration of 'struct MyClassPrivate'
    8. /usr/include/qt4/QtCore/qshareddata.h:171: warning: possible problem detected in invocation of delete operator:
    9. /usr/include/qt4/QtCore/qshareddata.h:171: warning: invalid use of incomplete type 'struct MyClassPrivate'
    10. myclass.h:25: warning: forward declaration of 'struct MyClassPrivate'
    11. /usr/include/qt4/QtCore/qshareddata.h:171: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.
    12. *** Exited with status: 2 ***
    To copy to clipboard, switch view to plain text mode 

    I traced that back to when I call:
    Qt Code:
    1. d->myclass = cls;
    To copy to clipboard, switch view to plain text mode 
    in my MyContainerThingy constructor;

    Any ideas?

  7. #7
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Segfault while using Pimpl idiom with Qt types.

    You didn't read document enough...

    You did

    d->myclass = cls

    but it has no operator=

    Add the following methods

    Qt Code:
    1. MyClass& operator=( const MyClass& rhs ) {
    2. d = rhs.d;
    3.  
    4. return *this;
    5. }
    6.  
    7. MyContainerThingy& operator=( const MyContainerThingy& rhs ) {
    8. d = rhs.d;
    9.  
    10. return *this;
    11.  
    12. }
    To copy to clipboard, switch view to plain text mode 

    You don't need MyClassPrivate(const MyClassPrivate &other) or MyClass(const MyClass &other);

  8. #8
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Ok I added the operator= methods and the MyClass example I gave compiles, but my real-world example was still failing.

    In the docs it says:
    The copy constructor is not strictly required here, because class EmployeeData is included in the same file as class Employee (employee.h). However, including the private subclass of QSharedData in the same file as the public class containing the QSharedDataPointer is not typical. Normally, the idea is to hide the private subclass of QSharedData from the user by putting it in a separate file which would not be included in the public file. In this case, we would normally put class EmployeeData in a separate file, which would not be included in employee.h. Instead, we would just predeclare the private subclass EmployeeData in employee.h this way:

    class EmployeeData;

    If we had done it that way here, the copy constructor shown would be required. Since the copy constructor is trivial, you might as well just always include it.
    So I put the copy-constructor back in and now it works.

  9. #9
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Sorry, I mean the private data copy ctor is not necessary, but the data object class needs both copy ctor and operator=

    That is:

    Needed:
    MyClass( const MyClass& )
    MyClass& operator=( const MyClass& )

    Not needed:
    MyClassPrivate( const MyClassPrivate& )

    This applies to your container class too.

  10. The following user says thank you to lni for this useful post:

    darkadept (12th June 2009)

  11. #10
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Yup! That makes a whole lotta sense and everything compiles fine.

    Thanks a ton!

  12. #11
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Segfault while using Pimpl idiom with Qt types.

    I also put this in the assignment operator to prevent self-assignment;

    (as per http://www.parashift.com/c++-faq-lit....html#faq-12.3)

    Qt Code:
    1. MyClass &MyClass::operator=(const MyClass &rhs) {
    2. if (this==&rhs) return *this; // <---- added this line
    3. d=rhs.d;
    4. return *this;
    5. }
    To copy to clipboard, switch view to plain text mode 

  13. #12
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Segfault while using Pimpl idiom with Qt types.

    Quote Originally Posted by darkadept View Post
    I also put this in the assignment operator to prevent self-assignment;

    (as per http://www.parashift.com/c++-faq-lit....html#faq-12.3)

    Qt Code:
    1. MyClass &MyClass::operator=(const MyClass &rhs) {
    2. if (this==&rhs) return *this; // <---- added this line
    3. d=rhs.d;
    4. return *this;
    5. }
    To copy to clipboard, switch view to plain text mode 
    That is a good practice. I don't sometimes do that since I know QSharedData will take care of it

Similar Threads

  1. Do you use Pimpl Idiom?
    By ComaWhite in forum General Discussion
    Replies: 5
    Last Post: 25th March 2009, 09:48

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.