2

Suppose I have a class X with private implementation Ximpl:

//Proj.h

#ifdef PROJ_EXPORTS
#define PROJ_API __declspec(dllexport)
#else
#define PROJ_API __declspec(dllimport)
#endif


//X.h

class PROJ_API X
{
  void foo();
  //..
private:
  class Ximpl;
  std::unique_ptr<Ximpl> x_impl;
}

This works perfectly, but generates the warning:

Compiler Warning (level 1) C4251:

warning C4251: 'X::Ximpl' : class 'std::unique_ptr>' needs to have dll-interface to be used by clients of class 'X::Ximpl'

I have tried to follow the suggested MSDN article, but 1). it didn't work. 2) I don't clearly understand the solution(workaround)

Any advice/explanation on how to get rid of these warnings (#pragma disable's are not an option :) ).

Why is it Level 1 warning?

NOTE: It turns out that if Ximpl is not declared in X scope, then it's possible to export a unique_ptr<Ximpl> after forward-declaration of Ximpl, but if it's in Xs scope, then it's a nested class and therefore can't be forward-declared..

However, for templated class even above solution (have non-nested impl class), seems to fail:

//X.h

template<typename T>
class PROJ_API X
{
  T foo();
  //..
private:
  class Ximpl;
  std::unique_ptr<Ximpl> x_impl;
}
Oleg Shirokikh
  • 3,447
  • 4
  • 33
  • 61

1 Answers1

2

Make sure your class X exports and declares non-inlined destructor. Otherwise the compiler implicitly declares inline destructor, which needs to know something about Ximpl in order to call its destructor. And with inline destructor, users of X also need to know how to destroy std::unique_ptr, which leads to the warning.

You can confirm this by checking that ~Ximpl() isn't called when X gets deleted, unless you export non-inlined ~X().

Tonttu
  • 1,811
  • 10
  • 8
  • - Thanks for a great advice, it makes perfect sense. However, I have non-inlined constructors implemented in each class. However, it doesn't get rid of the warning if I'm not exporting (as described in MSDN article) `unique_ptr`. In a template-class case, I can't even export the STL member (it's now 2-nested templates). Note, that it's possible to export instantiated template class, but not generic `X` – Oleg Shirokikh Feb 15 '15 at 02:13
  • Do you mean you have non-inlined destructors? – Tonttu Feb 15 '15 at 10:08
  • Yes, I meant 'destructors', not 'constructors'. However, I have both – Oleg Shirokikh Feb 15 '15 at 10:10