DLL导出导致唯一指针出现问题 [英] DLL exporting causing issues with unique pointers

查看:109
本文介绍了DLL导出导致唯一指针出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个文件:

Header.h

  #pragma一次#ifdef UNIQUEPTRISSUE_EXPORTS#定义UNIQUEPTRISSUE_API __declspec(dllexport)#别的#定义UNIQUEPTRISSUE_API __declspec(dllimport)#万一 

UniquePtrIssue.cpp

  #include"stdafx.h"#include"Header.h"#include< memory>#include< vector>类UNIQUEPTRISSUE_API ClassA {};类UNIQUEPTRISSUE_API ClassB {私人的:std :: vector< std :: unique_ptr< ClassA>>X;}; 

编译会引发以下错误:

1> d:\ program files(x86)\ microsoft visualstudio \ 2017 \企业\ vc \ tools \ msvc \ 14.14.26428 \ include \ xutility(2443):错误C2280:"std :: unique_ptr>& std :: unique_ptr< _Ty,std :: default_delete< _Ty >> :: operator =(conststd :: unique_ptr< _Ty,std :: default_delete< _Ty >>&)':试图引用已删除的功能1>与1> [1> _Ty = ClassA1>]

当访问 unique_ptr 的副本构造函数时,似乎会出现类似的问题,但似乎并不适用.

从两个类声明中删除 UNIQUEPTRISSUE_API / __ declspec(dllexport)似乎会使错误消失.

很显然,我不理解的 __ declspec(dllexport)声明正在发生某些事情.有什么方法可以在导出的类之间使用 unique_ptr s?

解决方案

使用 declspec(dllexport)声明类时,编译器必须生成该类的所有成员函数,包括默认构造函数,副本分配等功能,因为它不知道导入模块可能需要哪些构造函数.在C ++类中使用dllimport和dllexport 中对此进行了描述.

由于无法复制 unique_ptr ,因此将删除其复制构造函数和复制赋值运算符,并且当vector对象尝试使用它们时,会出现 C2280 错误./p>

当不包含 declspec(dllexport)时,编译器将仅生成实际使用的函数,从而避免了有问题的副本.

解决此问题的一种方法是导出单个类成员函数,这可能意味着将其中一些指定为默认值. virtual 函数无需导出,因为它们由vtable处理.

另一种解决方法是显式删除复制构造函数和复制分配运算符.由于这将阻止创建默认构造函数并移动构造函数/赋值函数,因此您可能需要将其中的默认值设置为默认值.

  class UNIQUEPTRISSUE_API ClassB {上市:ClassB(const ClassB&)=删除;ClassB& operator =(const ClassB&)=删除;//如果使用它们,则可能需要显式默认这些ClassB()=默认值;ClassB& operator =(ClassB&)=默认值;ClassB(ClassB&)=默认值;私人的:std :: vector< std :: unique_ptr< ClassA>>X;}; 

I've got two files:

Header.h

#pragma once

#ifdef UNIQUEPTRISSUE_EXPORTS
#define UNIQUEPTRISSUE_API __declspec(dllexport)   
#else  
#define UNIQUEPTRISSUE_API __declspec(dllimport)   
#endif 

UniquePtrIssue.cpp

#include "stdafx.h"

#include "Header.h"

#include <memory>
#include <vector>

class UNIQUEPTRISSUE_API ClassA {

};

class UNIQUEPTRISSUE_API ClassB {
private:
    std::vector<std::unique_ptr<ClassA>> x;
};

Compiling raises the following error:

1>d:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.14.26428\include\xutility(2443): error C2280: 'std::unique_ptr> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function 1> with 1> [ 1> _Ty=ClassA 1> ]

Similar issues seem to arise when the accessing the copy constructor of a unique_ptr but they don't seem to apply.

Removing the UNIQUEPTRISSUE_API/__declspec(dllexport) from both class declarations seems to make the error go away.

Obviously something is going on with the __declspec(dllexport) declaration that I don't understand. Is there any way I can use unique_ptrs between exported classes?

解决方案

When you declare a class with declspec(dllexport), the compiler must generate all of the member functions of the class, including the default constructors, copy assignment, etc functions since it doesn't know which ones may be needed by the importing module. This is described in Using dllimport and dllexport in C++ classes.

Since a unique_ptr cannot be copied, its copy constructor and copy assignment operators are deleted, and when the vector object tries to use them you get the C2280 error.

When you don't include declspec(dllexport), the compiler will only generate the functions that are actually used, and the problematic copies are avoided.

One way around this problem is to export the individual class member functions, which may mean specifying some of them as defaulted. virtual functions would not need to be exported, since they're handled by the vtable.

Another workaround is to explicitly delete the copy constructor and copy assignment operator. Since this will prevent the creation of a default constructor and move constructor/assignment functions, you may need to default those in.

class UNIQUEPTRISSUE_API ClassB {
public:
    ClassB(const ClassB &) = delete;
    ClassB &operator=(const ClassB &) = delete;
    // You may need to explicitly default these if they are used
    ClassB() = default;
    ClassB &operator=(ClassB &&) = default;
    ClassB(ClassB &&) = default;
private:
    std::vector<std::unique_ptr<ClassA>> x;
};

这篇关于DLL导出导致唯一指针出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆