Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::any for objects that can't be copy constructed

I have an object which holds a unique_ptr and as such can't be copy constructed without doing a deep copy (which I don't want).

I'd like to have std::any hold that object, but the only alternatives I've found is to either make std::any hold a pointer, which adds a useless indirection, or make my object have a unique ptr. The code bellow will hopefully illustrate my point:

//Compiled with clang++ -std=c++2a; clang version 5.0.0
#include <iostream>
#include <any>
#include <memory>

struct A {
        std::unique_ptr<int> m = std::make_unique<int>(11);
        A(A&& a): m(std::move(a.m)) {}
        A() {}
};

struct B {
        std::shared_ptr<int> m = std::make_shared<int>(11);
};


template<class T>
void use_any_ptr() {
        std::any a{new T{}};
        std::cout << *(std::any_cast<T*>(a)->m) << std::endl;
}

template<class T>
void use_any() {
        std::any a{T{}};
        std::cout << *(std::any_cast<T>(a).m) << std::endl;
}


int main() {
        use_any_ptr<A>(); // Workaround using a pointer
        use_any<B>(); // Workaround using shared pointer
        use_any<A>(); // Breaks because A has no cc no matching constructor for initialization of 'std::any'
}

As far as I understand the construction of std::any seems to require copying of the object, however I'm unsure why the object couldn't simply be moved.

Is there a way to work around this ? That is, other than using a shared_ptr, which means I'm basically expressing the "wrong thing" for the sake of creating the any object or passing std::any a pointer (which is an unneeded level of indirection, since std::any holds a void pointer to the type to being with as far as I can tell).

Is there a different implementation of any that could use the move ctr at creation instead of the copy ctr ?

Or am I being silly and not understanding the "real" problem here ?

like image 608
George Avatar asked Oct 20 '17 15:10

George


People also ask

How to avoid copy constructor in c++?

A cleaner solution: create a class where the default copy constructor and/or default copy assignment operator are deleted. Derive all your classes or the base class of the class hierarchies from this special class. Copy construction and/or copy assignment will now be disabled for all these classes automatically.

Does std :: Any copy?

The problem is simple here: std::any has a copy constructor and thus it requires the object contained is copy constructible.

How does the c++ copy constructor work?

Copy Constructor in C++ Copy constructor is used to initialize the members of a newly created object by copying the members of an already existing object. Copy constructor takes a reference to an object of the same class as an argument.


1 Answers

Or am I being silly and not understanding the "real" problem here ?

The problem is simple here: std::any has a copy constructor and thus it requires the object contained is copy constructible.

The way you can work around it is by defining a custom object that contains the pointer, that is copyable and that implements a proper logic for it (whatever proper means in your case, I can't see how you could copy an std::any and thus an object contained there that owns an std::unique_ptr, but maybe you can get away with it somehow in your case).

Otherwise rethink your design and try to get rid of the need of an std::any. It hasn't much uses indeed and probably you can get the same with a bit of template machinery or an std::variant or whatever

like image 139
skypjack Avatar answered Sep 19 '22 15:09

skypjack