开发者

Linker error while implementing pimpl idiom

Edited to provider a little more clarity. Apologies for confusing everyone.

This is under Windows.

I have a static library that开发者_运维百科 implements a class using the pimpl idiom. The pimpl header is not only used by the consuming code but it also links against the static library. Yet, when I compile the consuming code (.exe), the linker complains about unresolved externals on the implementation class that the pimpl header supposedly hides.

How can this be possible?

// Foo.lib

// Foo.h

class FooImpl;

class Foo
{
    std::shared_ptr<FooImpl> pimpl_;    
public:
    Foo();
};

// Foo.cpp

#include "Foo.h"
#include "FooImpl.h"

Foo::Foo() : pimpl_(new FooImpl())
{
}

// This is how its used in Bar.exe
// Bar.exe links against Foo.lib

// Bar.h

#include "Foo.h"

class Bar
{
    Foo access_foo_;
};

// Bar.cpp

#include "Bar.h"

When I compile/link Bar.exe, the linker complains that it is unable to resolve FooImpl. I forget what it said exactly since I don't have access to my work PC now but that's the gist of it. The error didn't make sense to me because the objective of going the pimpl route was so that Bar.exe didn't have to worry about FooImpl.

The exact error goes like this:

1>Foo.lib(Foo.obj) : error LNK2019: unresolved external symbol "public: __thiscall FooImpl::FooImpl(void)" (??0FooImpl@@QAE@XZ) referenced in function "public: __thiscall Foo::Foo(void)" (??0Foo@@QAE@XZ)


When you create a static library, the linker doesn't try to resolve everything that is missing; it assumes you'll be linking it later to another library, or that the executable itself will contribute some missing function. You must have forgotten to include some crucial implementation file in the library project.

The other possibility is that the pimpl implementation class is a template class. Templates don't generate code immediately, the compiler waits until you try to use them with the template parameters filled in. Your implementation file must include an instantiation of the template with the parameters that will be supported by your library.


After seeing your edit, the problem is that the Foo::Foo constructor needs access to the FooImpl::FooImpl constructor but the linker doesn't know where to find it. When the linker puts together the library, it doesn't try to resolve all of the references at that time, because it might have dependencies on yet another library. The only time that everything needs to be resolved is when it's putting together the executable. So even though Bar doesn't need to know about FooImpl directly, it still has a dependency on it.

You can resolve this in one of two ways: either export FooImpl from the library along with Foo, or make sure that Foo has access to FooImpl at compile time by putting them both in Foo.cpp with FooImpl coming before Foo.


1>Foo.lib(Foo.obj) : error LNK2019: unresolved external symbol "public: __thiscall FooImpl::FooImpl(void)" (??0FooImpl@@QAE@XZ) referenced in function "public: __thiscall Foo::Foo(void)" (??0Foo@@QAE@XZ)

The linker is complaining you that it can not find the definition of FooImpl::FooImpl(). You are calling the constructor here -

Foo::Foo() : pimpl_(new FooImpl())
                    // ^^^^^^^^^ Invoking the default constructor.

You just provided the declaration of default constructor but not it's definition.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜