Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can copy constructors of containers be defined as deleted for non-copyable value types?

If we have a container with non-copyable value type, such a container class still defines the copy constructor, just it may not be invoked.

using T = std::vector<std::unique_ptr<int>>;
std::cout << std::is_copy_constructible_v<T>; // prints out "1" (libstdc++)

This may cause "hidden" problems such as the one discussed here: Does Visual Studio 2017 need an explicit move constructor declaration?.

My question is if Standard library implementations may define such copy constructor as conditionally deleted, namely deleted in case of non-copyable value types. It would make perfect sense to me (at least until there are C++ concepts). Would such implementation be Standard-compliant?

like image 447
Daniel Langr Avatar asked Nov 08 '18 14:11

Daniel Langr


People also ask

What is true about copy constructors?

A copy constructor is a member function that initializes an object using another object of the same class. In simple terms, a constructor which creates an object by initializing it with an object of the same class, which has been created previously is known as a copy constructor.

What is deleted copy constructor?

The copy constructor and copy-assignment operator are public but deleted. It is a compile-time error to define or call a deleted function. The intent is clear to anyone who understands =default and =delete . You don't have to understand the rules for automatic generation of special member functions.

When should you delete copy constructor?

When to delete copy constructor and assignment operator? Copy constructor (and assignment) should be defined when ever the implicitly generated one violates any class invariant. It should be defined as deleted when it cannot be written in a way that wouldn't have undesirable or surprising behaviour.

What happens if a copy constructor is not defined?

Correctness/Semantics - if you don't provide a user-defined copy-constructor, programs using that type may fail to compile, or may work incorrectly.


2 Answers

This is mathematically impossible ever since vector got incomplete type support:

struct E {
    std::vector<E> e;
};

E is copyable iff std::vector<E> is copyable, and std::vector<E> is copyable iff E is copyable. Turtles all the way down.

Even before that, because the allocator's construct can mutilate the constructor arguments as it sees fit, and there's no way for the container to tell if something is "allocator-constructible", conditionally deleting the copy constructor would require some serious design work. The incomplete type support just put the nail in the coffin.

like image 130
T.C. Avatar answered Sep 29 '22 22:09

T.C.


For a short answer: no. If we look at the current specification (as of c++17) of std::vector, we have the following signature and description:

vector(const vector& other);

Copy constructor. Constructs the container with the copy of the contents of other. If alloc is not provided, allocator is obtained as if by calling std::allocator_traits::select_on_container_copy_construction(other.get_allocator()).

The copy constructor has the usual canonical signature and the description does not specify any SFINAE condition, so a conforming implementation should not impose stricter requirements such as conditional delete. Nevertheless, an instantiation error will occur if an explicit or implicit call to vector<unique_ptr<T>>'s copy ctor is attempted since the description implies element-wise copy. As such, vector<unique_ptr<T>> does not satisfy CopyConstructible requirement, which is very much like having a deleted copy constructor.

As far as I know, there is no syntactic support for a conditional delete but SFINAE conditions and the soon to come Constraints can achieve selective overload resolution. I would still strongly advise against using these on special operations. Special operations should be defined using their usual canonical signature.

like image 27
Julien Villemure-Fréchette Avatar answered Sep 30 '22 00:09

Julien Villemure-Fréchette