samedi 28 mai 2016

Copy constructors with move-only, but cloneable types in member containers

Assume that we have two types, T1 and T2.

T1 isn't important except the following facts:

  • it isn't copy constructible
  • it has a move constructor
  • we have an excellent function with the signature T1 copy(T1 const& orig), which creates a copy.

T2 can be simplified to the following class:

// T2.h
class T2 {
public:
    T2() { /* initializes the vector with something */ }
    T2(T2 const& other);
private:
    std::vector<T1> v;
}

// T2.cpp

T2::T2(T2 const& other) : ... {}

How would you implement this method, if you could only write to the ellipsis part, or to the global scope?

A simple real world use case - assuming the "you can't write anything between the curly braces" part is a real world restriction:

  • T2 is std::unique_ptr<anything>
  • copy is std::make_unique
  • anything has a copy constructor

I also have two additional requirements for the implementation:

  • performance. It shouldn't be (considerably) slower than the naive implementation with a for loop in the copy constructor's body.
  • readability. The entire point behind the question is to do something which is more clear/clean than the trivial for loop (e.g. imagine T2 with two or more member vectors).

And optional, but nice to have features:

  • something that's easily generalized to other containers
  • something that works with just iterators
  • something that's generic

A clarification: I know the question is trivially solvable with a std::vector<T1> copy_vec(std::vector<T1> const& orig) global function. Placing that function into an anonymous namespace within T2.cpp would also make it local, but I would argue against its readability, I think it wouldn't be better than the for loop at all. And it's clearly a bad solution if the copy constructor isn't in an implementation file but inlined in the header.

So a rephrasing of my question is:

  • Is there already something similar implemented, which I can just include?
  • If there is none, then why? I'm not saying I thought about every corner case, but I think this is something that possibly can be implemented in a nice generic way, and thanks to unique_ptr, it's a common enough case.

Aucun commentaire:

Enregistrer un commentaire