Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can classes with `std::variant` members be copied safely?

The following sample builds and runs properly with the line Container container2(container1); removed. It appears the copy constructor for std::variant itself is deleted, which makes my Container's copy constructor implicitly deleted.

Effectively, I'm asking:

  1. What is the proper way to store a std::variant as a member?
  2. What must be implemented in Container before safe copy/move assignment is allowed?
#include <string>
#include <variant>

class A {};

class Container {
 public:
  Container(int i) : data_(i) {}
  Container(float f) : data_(f) {}
  Container(std::string s) : data_(s) {}
  Container(std::unique_ptr<A> a) : data_(std::move(a)) {}
  std::variant<int, float, std::string, std::unique_ptr<A>> data_;
};

int main() {
  Container container1{3};
  
  // error: call to implicitly-deleted copy constructor of 'Container'
  // 
  // copy constructor of 'Container' is implicitly deleted because
  // field 'data_' has a deleted copy constructor
  Container container2(container1);

  return 0;
}
like image 777
Ευάριστος Avatar asked Oct 10 '20 01:10

Ευάριστος


2 Answers

cppreference has this to say about std::variant's copy constructor:

Copy constructor. [...] This constructor is defined as deleted unless std::is_copy_constructible_v<T_i> is true for all T_i in Types. [...]

In other words, it is not deleted unless one or more of the types that the std::variant can contain is not copyable for whatever reason. In your case, it's the std::unique_ptr that's causing the problem. Perhaps std::shared_ptr would be more appropriate.

like image 142
Paul Sanders Avatar answered Oct 13 '22 01:10

Paul Sanders


Extending Paul Sanders' answer: what kind of copy do you want?

If it is a shallow copy, use shared_ptr<A>.

If it is a deep copy, why not have variant<..,A>? If the reason is that A is polymorphic, then the real problem is cloning each of the derived classes. You have to create your own mechanism for the cloning and your own copyable smart pointer to use it - as far as I know, there is nothing in the standard library to help you.

like image 37
Eugene Avatar answered Oct 13 '22 01:10

Eugene