DLL 导出导致唯一指针出现问题
DLL exporting causing issues with unique pointers
我有两个文件:
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;
};
编译出现以下错误:
1>d:\program files (x86)\microsoft visual
studio17\enterprise\vc\tools\msvc.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> ]
访问 unique_ptr
的复制构造函数时似乎会出现类似的问题,但它们似乎并不适用。
从两个 class 声明中删除 UNIQUEPTRISSUE_API
/__declspec(dllexport)
似乎可以使错误消失。
显然,__declspec(dllexport)
声明发生了一些我不理解的事情。有什么办法可以在导出的 class 之间使用 unique_ptr
s 吗?
当你用 declspec(dllexport)
声明一个 class 时,编译器必须生成 class 的所有成员函数,包括默认构造函数、复制赋值等函数,因为它不知道导入模块可能需要哪些。 Using dllimport and dllexport in C++ classes.
中对此进行了描述
由于无法复制 unique_ptr
,因此删除了其复制构造函数和复制赋值运算符,当向量对象尝试使用它们时,您会收到 C2280
错误。
当您不包含 declspec(dllexport)
时,编译器将只生成实际使用的函数,避免有问题的副本。
解决此问题的一种方法是导出单个 class 成员函数,这可能意味着将其中一些指定为默认成员函数。 virtual
不需要导出函数,因为它们由 vtable 处理。
另一种解决方法是显式删除复制构造函数和复制赋值运算符。由于这将阻止创建默认构造函数并移动 constructor/assignment 函数,因此您可能需要将它们默认为.
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;
};
您可以以不同的方式公开 class:
class ClassB {
private:
std::vector<std::unique_ptr<ClassA>> x;
public:
UNIQUEPTRISSUE_API ClassB(ClassB&&) {
}
UNIQUEPTRISSUE_API ClassB& operator==(ClassB&&) {
return* this;
}
private:
}
即:不要导出整个 class,而是导出单个函数。
我在 vs2010 和 vs2017
上试了一下
我有两个文件:
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;
};
编译出现以下错误:
1>d:\program files (x86)\microsoft visual studio17\enterprise\vc\tools\msvc.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> ]
访问 unique_ptr
的复制构造函数时似乎会出现类似的问题,但它们似乎并不适用。
从两个 class 声明中删除 UNIQUEPTRISSUE_API
/__declspec(dllexport)
似乎可以使错误消失。
显然,__declspec(dllexport)
声明发生了一些我不理解的事情。有什么办法可以在导出的 class 之间使用 unique_ptr
s 吗?
当你用 declspec(dllexport)
声明一个 class 时,编译器必须生成 class 的所有成员函数,包括默认构造函数、复制赋值等函数,因为它不知道导入模块可能需要哪些。 Using dllimport and dllexport in C++ classes.
由于无法复制 unique_ptr
,因此删除了其复制构造函数和复制赋值运算符,当向量对象尝试使用它们时,您会收到 C2280
错误。
当您不包含 declspec(dllexport)
时,编译器将只生成实际使用的函数,避免有问题的副本。
解决此问题的一种方法是导出单个 class 成员函数,这可能意味着将其中一些指定为默认成员函数。 virtual
不需要导出函数,因为它们由 vtable 处理。
另一种解决方法是显式删除复制构造函数和复制赋值运算符。由于这将阻止创建默认构造函数并移动 constructor/assignment 函数,因此您可能需要将它们默认为.
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;
};
您可以以不同的方式公开 class:
class ClassB {
private:
std::vector<std::unique_ptr<ClassA>> x;
public:
UNIQUEPTRISSUE_API ClassB(ClassB&&) {
}
UNIQUEPTRISSUE_API ClassB& operator==(ClassB&&) {
return* this;
}
private:
}
即:不要导出整个 class,而是导出单个函数。 我在 vs2010 和 vs2017
上试了一下