Search code examples
c++pimpl-idiom

Pimpl not working


This is a very noobish mistake, but I dont know whats happening here.

There are loads of pimpl examples but I dont understand why this isn't working (this was one of the examples more or less but I dont see the difference).

I have a very simple Pimpl example, but it wont work.

// Foo.hpp
#include <boost/scoped_ptr.hpp>

class Foo
{
 struct Bar;
 //boost::scoped_ptr<Bar> pImpl;
 Bar* pImpl;

public:
 Foo();
 ~Foo() {}

 int returnValue();

private:

};

and

// Foo.cpp
#include "foo.hpp"

struct Foo::Bar
{ 
 Bar() {}
 ~Bar() {}
 int value;
};

Foo::Foo() : pImpl(new Bar())
{
 pImpl->value = 7;
}

int Foo::returnValue() {
 return *pImpl->value;
}

Compiling this gives me the error. C2100: illegal indirection.

Thanks.


Solution

  • int returnValue() should be a member function:

    //  vvvvv
    int Foo::returnValue() {
     return pImpl->value; // no need to dereference, value isn't a pointer
    }
    

    You need to define your constructor, copy-constructor, copy assignment operator, and destructor after the implementation class has been defined. (Otherwise the implicit destructor is dangerous, and scoped_ptr won't let you do that):

    // Foo.hpp
    #include <boost/scoped_ptr.hpp>
    
    class Foo
    {
        struct Bar;
        boost::scoped_ptr<Bar> pImpl;
    
    public:
        Foo();
        ~Foo();
    
        int returnValue(); // could be const (so should be)
    
    private:
        // just disable copying, like scoped_ptr
        Foo(const Foo&); // not defined
        Foo& operator=(const Foo&); // not defined
    };
    

    And:

    // Foo.cpp
    #include "foo.hpp"
    
    struct Foo::Bar
    { 
        int value;
    };
    
    Foo::Foo() :
    pImpl(new Bar())
    {
        pImpl->value = 7;
    }
    
    Foo::~Foo()
    {
        // okay, Bar defined at this point; scoped_ptr can work
    }
    
    int Foo::returnValue()
    {
        return pImpl->value;
    }