Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a vector of unique pointers in a dll exported class with Visual Studio

A simple example

class __declspec(dllexport) A
{
public:
    vector<unique_ptr<int>> v;
};

Error in VS2013 compilation for deleted copy constructor of unique_ptr. If I remove __declspec(dllexport), it is fine. If I use only unique_ptr<int> v, it is fine too. Is this a compiler bug? Any way to work around it? Thanks.

You may try it on http://webcompiler.cloudapp.net/ with the following complete code

#include <iostream>
#include <vector>
#include <memory>
using namespace std;

class __declspec(dllexport) A
{
public:
    vector<unique_ptr<int>> v;
};

int main()
{
   cout << "Hello World" << endl; 
}

yielding the compiler error:

Compiled with /EHsc /nologo /W4 /c
main.cpp
main.cpp(9): warning C4251: 'A::v': class 'std::vector<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' needs to have dll-interface to be used by clients of class 'A'
        with
        [
            _Ty=int
        ]
c:\tools_root\cl\inc\xutility(2144): error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
        with
        [
            _Ty=int
        ]
c:\tools_root\cl\inc\memory(1430): note: see declaration of 'std::unique_ptr<int,std::default_delete<_Ty>>::operator ='
        with
        [
            _Ty=int
        ]
c:\tools_root\cl\inc\xutility(2165): note: see reference to function template instantiation '_OutIt std::_Copy_impl<_InIt,_OutIt>(_InIt,_InIt,_OutIt,std::_Nonscalar_ptr_iterator_tag)' being compiled
        with
        [
            _OutIt=std::unique_ptr<int,std::default_delete<int>> *,
            _InIt=std::unique_ptr<int,std::default_delete<int>> *
        ]
c:\tools_root\cl\inc\vector(973): note: see reference to function template instantiation '_OutIt std::_Copy_impl<std::unique_ptr<int,std::default_delete<_Ty>>,std::unique_ptr<_Ty,std::default_delete<_Ty>>*>(_InIt,_InIt,_OutIt)' being compiled
        with
        [
            _OutIt=std::unique_ptr<int,std::default_delete<int>> *,
            _Ty=int,
            _InIt=std::unique_ptr<int,std::default_delete<int>> *
        ]
c:\tools_root\cl\inc\vector(956): note: while compiling class template member function 'std::vector<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::operator =(const std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)'
        with
        [
            _Ty=int
        ]
main.cpp(10): note: see reference to function template instantiation 'std::vector<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::operator =(const std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)' being compiled
        with
        [
            _Ty=int
        ]
main.cpp(9): note: see reference to class template instantiation 'std::vector<std::unique_ptr<int,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' being compiled
        with
        [
            _Ty=int
        ]
like image 271
user1899020 Avatar asked Apr 10 '15 15:04

user1899020


1 Answers

It appears adding __declspec(dllexport) forces the compiler to define the implicitly-declared copy constructor and copy assignment operator (normally, this only happens if they're used). These in turn call the copy constructor/assignment operator of v. But the copy operations of std::vector<T> are ill-formed for a non-copyable T, such as std::unique_ptr. Hence the error.

When the member is just std::unique_ptr, the problem does not occur, because that has copy operations explicitly deleted and so the default copy operations of A become deleted as well.

So the issue is solved if you explicitly delete the copy operations:

class __declspec(dllexport) A
{
public:
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    vector<unique_ptr<int>> v;
};

Of course, if you want copy functionality, defining them yourself would help as well.

like image 175
Angew is no longer proud of SO Avatar answered Oct 16 '22 02:10

Angew is no longer proud of SO