问题
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_ptr
s between exported classes?
回答1:
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;
};
回答2:
You can expose class differently:
class ClassB {
private:
std::vector<std::unique_ptr<ClassA>> x;
public:
UNIQUEPTRISSUE_API ClassB(ClassB&&) {
}
UNIQUEPTRISSUE_API ClassB& operator==(ClassB&&) {
return* this;
}
private:
}
i.e: don't export the entire class, but the single function. I try this on vs2010 and vs2017
来源:https://stackoverflow.com/questions/51033325/dll-exporting-causing-issues-with-unique-pointers