我有两个文件:
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 studio \ 2017 \企业\ vc \ tools \ msvc \ 14.14.26428 \ include \ xutility(2443): 错误C2280:“ std :: unique_ptr> &std :: unique_ptr <_Ty,std :: default_delete <_Ty >> :: operator =(const std :: unique_ptr <_Ty,std :: default_delete <_Ty >>&)':尝试 引用已删除的功能 1>与 1> [ 1> _Ty = ClassA 1>]
相似的问题似乎在访问unique_ptr
的副本构造函数时出现,但似乎并不适用。
从两个类声明中删除UNIQUEPTRISSUE_API
/ __declspec(dllexport)
似乎会使错误消失。
显然,__declspec(dllexport)
声明正在发生某些我不理解的事情。有什么方法可以在导出的类之间使用unique_ptr
?
答案 0 :(得分:2)
当您使用declspec(dllexport)
声明一个类时,编译器必须生成该类的所有成员函数,包括默认构造函数,副本分配等函数,因为它不知道可能需要哪些成员函数。导入模块。这在Using dllimport and dllexport in C++ classes中有描述。
由于无法复制unique_ptr
,因此将删除其复制构造函数和复制赋值运算符,并且当vector对象尝试使用它们时,会出现C2280
错误。
当您不包括declspec(dllexport)
时,编译器将仅生成实际使用的函数,从而避免了有问题的副本。
解决此问题的一种方法是导出单个类成员函数,这可能意味着将其中一些指定为默认值。 virtual
函数无需导出,因为它们由vtable处理。
另一个解决方法是显式删除复制构造函数和复制分配运算符。由于这将阻止创建默认构造函数并移动构造函数/赋值函数,因此您可能需要在其中使用默认值。
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;
};
答案 1 :(得分:1)
您可以不同地公开类:
class ClassB {
private:
std::vector<std::unique_ptr<ClassA>> x;
public:
UNIQUEPTRISSUE_API ClassB(ClassB&&) {
}
UNIQUEPTRISSUE_API ClassB& operator==(ClassB&&) {
return* this;
}
private:
}
即:不导出整个类,而是导出单个函数。 我在vs2010和vs2017上尝试过