30

The explicit keyword is recommended for all most constructors which can be called with one argument, except for copy constructors.

For copy constructors, it has an use (to forbid implicit copying via function call, return, etc), but it's not what's usually wanted.

What about move constructors? Is there any reasonable use case to make them explicit? What's the good practice here?

Kos
  • 70,399
  • 25
  • 169
  • 233
  • What is the difference between a "copy constructor" and a "constructor that can be called with one argument"? I just had a moments confusion with DeadMGs answer because I thought these were the same thing. This *is* just the way it's used, and (other than "explicit") not how the constructor is declared, yes? Or have I gone insane? –  Jul 20 '11 at 08:46
  • 3
    @Steve314: A single-argument copy constructor is specifically a constructor `T([const] [volatile] T&)`. 12.8/2. `T(int)` is a constructor that can be called with one argument, but is not a copy constructor because it doesn't "copy" an instance of `T`. – Steve Jessop Jul 20 '11 at 08:48
  • @Steve Jessop - yes, of course. Obviously I have gone brain dead. –  Jul 20 '11 at 08:51
  • Thanks for the answers! So can we agree that there's no reasonable (i.e. beneficial in an obvious way) reason to make it explicit? – Kos Jul 20 '11 at 10:20
  • It's also recommended for constructors which can only be called for multiple arguments in C++0x. – Johannes Schaub - litb Jul 21 '11 at 08:51
  • @Johannes Schaub, you mean there are cases in C++0x when the `explicit` keyword would make a difference on such constructors? Can you give an example? – Kos Jul 22 '11 at 13:38

5 Answers5

29

An explicit move constructors can affect compatibility with e.g. Standard algorithms. For instance, std::swap<T> requires that T be MoveConstructible. In turn, MoveConstructible is specified in terms of an expression, namely T u = rv; (where rv is an rvalue of type T).

If there is neither a non-explicit copy constructor nor a non-explicit move constructor for a given type then T u = rv; is invalid and that type can't be used with std::swap. (In this particular instance however it is possible to specialize std::swap to provide the desired functionality, e.g. by using T u(rv);).

Put more simply, an explicit move or copy constructor defies expectations and can't be used as well with generic code.

Some other parts of the Standard library that put a MoveConstructible requirement:

  • the deleter of unique_ptr<T, D>
  • call wrappers, used in e.g. bind (all the decayed types that are passed are concerned)
  • thread, async, call_once (all specified in terms of call wrappers)
  • sort, stable_sort, nth_element, sort_heap
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
7

You probably want an implicit move constructor for the majority of uses. They generally fall into the same categories as copy constructors. Explicit isn't recommended for all one-argument constructors, but it is recommended for most. Move constructors are not on that list.

Puppy
  • 144,682
  • 38
  • 256
  • 465
7

The explicit keyword is recommended for (single argument) converting constructors, to avoid surprising conversions in unexpected places.

Copy constructors and move constructors are hardly "surprising" in that sense. They happen largely where expected. If you don't want them, I would expect them to be marked =delete rather than made explicit.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
2

The actual question is how explicit move constructor could possibly be used? It wouldn't be able to be invoked on rvalues, so compiler would have to always select a copy constructor, if available, or fail to compile.

Edit: here is the link to example: http://www.ideone.com/nm7KM

Gene Bushuyev
  • 5,512
  • 20
  • 19
  • @Luc: it's a good one! and probably the only way explicit move constructor can be invoked. – Gene Bushuyev Jul 21 '11 at 16:53
  • +1 for a good question, Gene :) And more props for Luc for the answer (it could be useful if you would add it to your post for any future reference). Thanks! – Kos Jul 25 '11 at 10:47
0

When returning by value from a function, an implicit move constructor can usually make the process more efficient.

Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • A bit off-topic but good point, actually- I think that's a reason to make move constructors inline if possible. – Kos May 01 '12 at 14:32