Linker error while implementing pimpl idiom

穿精又带淫゛_ 提交于 2021-02-11 13:07:56

问题


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)


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/7616281/linker-error-while-implementing-pimpl-idiom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!