Search code examples
c++pimpl-idiom

Problems with compiling a pimpl idiom code


I've been trying to have a go at a 'pimpl' idiom but I just can't get the darned thing to compile.

On Linux Mint with g++ v. 4.6.3 I get the following error:

$ g++ main.cc 
/tmp/ccXQ9X9O.o: In function `main':
main.cc:(.text+0xd7): undefined reference to `Person::Person(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)'
collect2: ld returned 1 exit status

This is my code:

person.hh

#ifndef PERSON_HH
#define PERSON_HH

#include <tr1/memory>
#include <string>

class Person
{
    private:
    class PersonImpl;
    std::tr1::shared_ptr<PersonImpl> pImpl;

    public:
    Person(const std::string& name, int age=0);

    ~Person();

    const std::string& get_name() const;

    int get_age() const;
};

#endif

person.cc

#include <string>
#include "person.hh"

class Person::PersonImpl
{
    public:
    std::string name;
    int age;

    PersonImpl(const std::string& n, int a) : name(n), age(a) {}
};

Person::Person(const std::string& name, int age) : pImpl(new PersonImpl(name, age)) {}

Person::~Person() {}

const std::string& Person::get_name() const { return pImpl->name; }

int Person::get_age() const { return pImpl->age; }

main.cc

#include <iostream>
#include "person.hh"

int main()
{   
    const std::string name = "foo";
    Person p(name, 50);

    return 0;
}

Apart from the code mistakes, could you please advise on the approach I've taken to mimicking a 'pimpl' idiom? Does this conform to it?


Solution

  • The problem seems to be due to the fact that your person.cc file is not being linked in. You may have to adjust your project configuration to fix this.

    Apart from the code mistakes, could you please advise on the approach I've taken to mimicking a 'pimpl' idiom? Does this conform to it?

    I would suggest using unique_ptr rather than shared_ptr, since the PersonImpl implementation object is owned exclusively by the Person object:

    class Person
    {
    private:
        class PersonImpl;
        std::tr1::unique_ptr<PersonImpl> pImpl;
    //            ^^^^^^^^^^
        // ...
    };
    

    Apart from this, you should make use of constructor initialization lists to initalize the pImpl data member:

    Person::Person(const std::string& name, int age)
        : pImpl(new PersonImpl(name, age))
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    {
    }