dll中的std :: unique_ptr pimpl使用visual studio生成C4251

kit*_*kun 20 c++ pimpl-idiom visual-c++ c++11

这不是一个突破性的问题,但我喜欢从警告中清除我的代码,所以这让我很紧张.

我一直在使用c ++ 11版本的pimpl成语以通常的方式隐藏我的库的类实现.

// dll header
class FrameworkImpl;

class EXPORT_API Framework
{
    Framework(const Framework&) = delete;
    Framework& operator=(const Framework&) = delete;
    Framework(Framework&&) = delete;
    Framework& operator=(Framework&&) = delete;

public:
    Framework();
    ~Framework();

private:
    std::unique_ptr<FrameworkImpl> impl_;
};

// application implementation
int main()
{
    std::unique_ptr<Framework> test = std::make_unique<Framework>();
}
Run Code Online (Sandbox Code Playgroud)

一切都会好的,但我会继续收到警告:

warning C4251: 'Framework::impl_': class 'std::unique_ptr<FrameworkImpl,std::default_delete<_Ty>>' needs to have dll-interface to be used by clients of class 'Framework'
Run Code Online (Sandbox Code Playgroud)

所以我试着添加:

template class EXPORT_API std::unique_ptr<FrameworkImpl>;
Run Code Online (Sandbox Code Playgroud)

在前向声明之前,警告只会改为:

warning C4251: 'std::_Unique_ptr_base<_Ty,_Dx>::_Mypair': class 'std::_Compressed_pair<_Dx,FrameworkImpl *,true>' needs to have dll-interface to be used by clients of class 'std::_Unique_ptr_base<_Ty,_Dx>'
Run Code Online (Sandbox Code Playgroud)

自VS2010以来,我一直在看这个问题,我无法找到解决这个问题的好方法.在gcc或clang上没有问题,它会让我心碎使用旧的原始指针版本..

Mat*_*jek 15

这是DLL类的一个非常常见的问题,它使用来自的模板std.

为什么会这样?

原因很简单:标准仅规定了保证,限制要求.因此,您可以确定,每个C++ 11编译器都将提供std::unique_ptr,其外观和工作方式与本页所述相同.但其他一切都依赖于实现.

主要问题是,不同的实现可能(并且通常会)对特定类型使用完全不同的结构.它们使用其他辅助变量,不同的布局等.即使在同一编译器的两个版本之间,这可能也不同.因此,如果客户端代码以任何方式触及类的成员变量,则需要为它们提供DLL接口.这适用于dllexported类使用的所有类型.

您可能希望阅读MSDN上的这篇文章,它描述了容器的这个问题.

此问题可以简化为以下内容:

  • 如果客户端代码无法访问您的数据,请禁用此警告.
  • 如果您有要由客户端代码使用的成员,请创建包装,即dllexport编辑或使用dllexported方法的其他间接.
  • 通常,您可以使用PIMPL来隐藏非DLL类型,但在您的情况下它不适用,因为您使用不可导出的类型来实际实现 PIMPL.

进一步阅读:


小智 6

您可以仅导出公共方法,而不是导出整个类:

class Framework
{
    Framework(const Framework&) = delete;
    Framework& operator=(const Framework&) = delete;
    Framework(Framework&&) = delete;
    Framework& operator=(Framework&&) = delete;

public:
    EXPORT_API Framework();
    EXPORT_API ~Framework();

private:
    std::unique_ptr<FrameworkImpl> impl_;
};
Run Code Online (Sandbox Code Playgroud)


kit*_*kun 0

解决方案是在 impl 声明和 Olga Perederieieva 答案的组合之后声明构造函数/析构函数

详细说明和示例请参考本网站

标题:

#include <memory>

class FridgeImpl;

class Fridge
{
public:
   DLL_EXPORT Fridge();
   DLL_EXPORT ~Fridge();
   DLL_EXPORT void coolDown();
private:
   std::unique_ptr<FridgeImpl> impl_;
};
Run Code Online (Sandbox Code Playgroud)

执行:

#include "Engine.h"
#include "Fridge.h"

class FridgeImpl
{
public:
   void coolDown()
   {
      /* ... */
   }
private:
   Engine engine_;
};

Fridge::Fridge() : impl_(new FridgeImpl) {}

Fridge::~Fridge() = default;
Run Code Online (Sandbox Code Playgroud)