Home > Back-end >  dllexport a type with a std container of std::unique_ptr results in error C2280
dllexport a type with a std container of std::unique_ptr results in error C2280

Time:08-11

I'm trying to dllexport a type with a std container of std::unique_ptr member, f.e.

struct __declspec(dllexport) C {
    std::vector<std::unique_ptr<int>> c_;
};

but whatever i try, msvc always complains about

msvc/14.33.31629/include\xutility(4145): error C2280: 'std::unique_ptr<int,std::default_delete<int>> &std::unique_ptr<int,std::default_delete<int>>::operator =(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function

The container type doesn't matter; the error is almost identical (always C2280) for vector, map, and others.

However, as soon as a std::unique_ptr member is added to the type, f.e.

struct __declspec(dllexport) C {
    std::vector<std::unique_ptr<int>> c_;
    std::unique_ptr<int> rup;
};

the error disappears.

I have no clue if this is the intended behavior, what causes this problem and how it can be fixed without adding a random std::unique_ptr member. What am i missing?

Demo

CodePudding user response:

When you have a member std::vector<std::unique_ptr<int>> c_;, the compiler will provide a copy assignment operator C& operator=(const C&) that will try to copy the c_ member. This will fail to compile if it is actually used, since the elements of c_ can't be copied.

__declspec(dllexport) seems to try to create this implicitly-declared function (maybe to export it? Though it doesn't seem to actually do that), which fails.

When you add std::unique_ptr<int> rup;, this is a type without a copy constructor at all, so the implicit operator=(const C&) is suppressed (The move assign operator C& operator=(C&&) can still be used).

You can get rid of the implicit copy-assign operator by declaring a move-assign operator or a move constructor:

struct __declspec(dllexport) C {
    std::vector<std::unique_ptr<int>> c_;
    C(C&&) = default;
};

Or by inheriting from a move-only type/having a move-only member:

struct move_only { constexpr move_only(move_only&&) noexcept = default; };

struct __declspec(dllexport) C : private move_only {
    std::vector<std::unique_ptr<int>> c_;
};

CodePudding user response:

unique_ptr is not a copyable type (or else it wouldn't be unique). The error message is complaining that something is trying to access the unique_ptr's copy assignment operator, which has been disabled.

In your first example, your C struct has only copyable members, so a default copy constructor and copy assignment operator are generated for it by the compiler. Which then fails if they are invoked since unique_ptr can't be copied.

Whereas in your second example, your C struct has a non-copyable member, so the default copy constructor and copy assignment operator are not generated by the compiler.

  • Related