9.13 — Converting constructors, explicit, and delete

By default, C++ will treat any constructor as an implicit conversion operator. Consider the following case:

Although function makeNegative() is expecting a Fraction, we’ve given it the integer literal 6 instead. Because Fraction has a constructor willing to take a single integer, the compiler will implicitly convert the literal 6 into a Fraction object. It does this by initializing makeNegative() parameter f using the Fraction(int, int) constructor.

Since f is already a Fraction, the return value from makeNegative() is copy-constructed back to main, which then passes it to overloaded operator<<.

Consequently, the above program prints:

Copy constructor called

This implicit conversion works for all kinds of initialization (direct, uniform, and copy).

Constructors eligible to be used for implicit conversions are called converting constructors (or conversion constructors). Prior to C++11, only constructors taking one parameter could be converting constructors. However, with the new uniform initialization syntax in C++11, this restriction was lifted, and constructors taking multiple parameters can now be converting constructors.

The explicit keyword

While doing implicit conversions makes sense in the Fraction case, in other cases, this may be undesirable, or lead to unexpected behaviors:

In the above example, the user is trying to initialize a string with a char. Because chars are part of the integer family, the compiler will use the converting constructor MyString(int) constructor to implicitly convert the char to a MyString. The program will then print this MyString, to unexpected results.

One way to address this issue is to make constructors (and conversion functions) explicit via the explicit keyword, which is placed in front of the constructor’s name. Constructors and conversion functions made explicit will not be used for implicit conversions or copy initialization:

The above program will not compile, since MyString(int) was made explicit, and an appropriate converting constructor could not be found to implicitly convert ‘x’ to a MyString.

However, note that making a constructor explicit only prevents implicit conversions. Explicit conversions (via casting) are still allowed:

Direct or uniform initialization will also still convert parameters to match (uniform initialization will not do narrowing conversions, but it will happily do other types of conversions).

Rule: Consider making your constructors and user-defined conversion member functions explicit to prevent implicit conversion errors

In C++11, the explicit keyword can also be used with conversion operators.

The delete keyword

In our MyString case, we really want to completely disallow ‘x’ from being converted to a MyString (whether implicit or explicit, since the results aren’t going to be intuitive). One way to partially do this is to add a MyString(char) constructor, and make it private:

However, this constructor can still be used from inside the class (private access only prevents non-members from calling this function).

A better way to resolve the issue is to use the “delete” keyword (introduced in C++11) to delete the function:

When a function has been deleted, any use of that function is considered a compile error.

Note that the copy constructor and overloaded operators may also be deleted in order to prevent those functions from being used.

9.14 -- Overloading the assignment operator
9.12 -- Copy initialization

66 comments to 9.13 — Converting constructors, explicit, and delete

  • Anthony

    This has got me stumped:

    I do not understand why the last line fails to compile if the init list constructor is made explicit:
    "error: converting to 'VecArray' from initializer list would use explicit constructor 'VecArray::VecArray(const std::initializer_list<std::vector<double> >&)'|"

    I imagine it's because an implicit conversion is somehow required, but where/how/why?

    • Hi Anthony!

      Make sure you followed lesson 0.10 and 0.11, there are several narrowing casts in your code.

      You can get around this by calling the constructor explicitly.

      • Anthony


        OK, I thought that VecArray's init list constructor is there precisely because it accepts a std::initializer_list<std::vector<double>> parameter - i.e. that no conversion is necessary - in the same way that this constructor:

        doesn't do any conversion because the constructor is precisely there to accept an int - i.e. that no conversion is necessary.

        And that therefore neither of these need to be explicit to work properly. What is the error in my thinking?

        • (1) is fine. @A can be constructed from an int. We're explicitly calling the constructor.

          (2) is an error. Each element in the curly brackets has to be an @A. @i is an int, and although it could be converted to an @A, we disallowed this conversion by marking the constructor 'explicit', ie. it cannot be called implicitly.

          (3) is fine. @a is an @A already, no conversion has to be made.

          (4) is fine, because we're explicitly calling the constructor.

          The same is happening in your @VecArray, where
          int is std::initializer_list<std::vector<double>>
          A is VecArray

  • David

    In the first example, your explanation says
    "It does this by copy-initializing makeNegative() parameter f using the Fraction(int, int) constructor."
    but isn't the copy constructor only called once when it returns a Fraction object (as the output suggests)? So is it correct to say that it's copy-initializing the parameter, wouldn't it rather just be calling its constructor to make the parameter?

  • Asgar


    I am trying to understand why we delete this inside the class definition:

    That constructor does not exist by default. Do you mean to say that, before engaging in any sort of conversion, the compiler will first see if there is a matching constructor like MyString(char) and then it will stumble on MyString(char) = delete; even though MyString(char) does not really exist?

    (Actually, that constructor existed in the previous version of the class and then you removed it.)

    • Alex

      Yes -- constructors have two jobs: first, to determine what kind of objects can be created, and second, to do any initialization work required.

      If a match constructor is inaccessible for some reason, objects can't be created using that constructor. When we delete a constructor, we're telling the compiler to error out if it encounters any use of that constructor. So in this case, when we try to create MyString mine('x'), the compiler will match to the deleted constructor, and then error out.

  • Jon

    Hello! I have a question about the statement "overloaded operators may also be deleted in order to prevent those functions from being used"...

    Isn't that the same as just not writing the overloaded operator function at all? Why would you need to write the operator overload function and then "delete" it with the keyword? Or am I misunderstanding what you meant by that line?

    Thanks very much!

    • Alex

      In some cases, C++ will provide default implementations of operators if you do not define them yourself (e.g. an assignment operator). Explicitly deleting them prevents this.

  • i don't understand in explicit section why if i made all my constructors explicit (so i make all of them deny implicit conversion)

    shouldn't there be an implicit conversion in the last 2 cases also ?

    • Alex

      This is one of those areas where C++ is a bit weird. Implicit conversions and copy initialization only consider non-explicit constructors and conversion functions. However, direct and uniform initialization consider all constructors and conversion functions.

      It sounds like I need to do a better job of making this clearer. I'll update the article.

  • Quoxa

    Just a very small typo:
    "... an appropriate converting constructor could not be found to implicitly convert ‘q’ to a MyString.".

    In the examples above, you used 'x' instead of 'q'

  • Saumitra Kulkarni

    In the code below that we discussed throughout the lesson :-

    Now if we want to resize the m_string member(which is initialized to "hello") of the same object 'mine' how would we do that?

    • nascardriver

      Hi Saumitra!

      With the code as it is this can't be done. All you can do is assign another string to to @mine.

      If you want to resize the string without assigning it a new string you'll have to add a function @MyString to do so.

  • >>> The above program will not compile, since MyString(int) was made explicit, and an appropriate converting constructor could not be found to implicitly convert ‘x’ to a MyString.

    Hi Alex,

    Just wondering if there's an error in the above line in this article. The code snippet above this line does not have the character 'x' anywhere. Did you instead mean this at line 32?

    MyString x = 'x';

  • Stephen

    I notice you are very responsive with questions. I'm impressed, nice work.

    Also nice work on the tutorials.

  • Aitor

    Hi  Alex,

    I just have one question about the last sentence:

    Note that the copy constructor and overloaded operators may also be deleted in order to prevent those functions from being used.

    I need some help to understand it. You mean, we have to make a copy constructor an delete it? and also the operators we overload?. But then we'll no have any of those if we want to use them for any reason. I would appreciate an example or, if its too much inconveniences, just a more detailed explanation.

    Thanks for the amazing tutorials!!!, and sorry for the disconfort caused. Greatings from Spain!!

    • Alex

      You can delete pretty much any function in a class in the same way we deleted the MyString(char) constructor in the example above. You just declare the function prototype, and put = delete at the end.

      You obviously shouldn't delete any functions you think you might need! But, let's say we had an array class that held 1 million elements. That's huge. Without any protection, the user might try to pass that array by value, which would cause expensive copies to be made. By deleting certain functions (e.g. the copy constructor), we can prevent the class from being passed by value -- if the user tries, they'll get a compile error. This will help remind them that they shouldn't be doing that in the first place (and that pass by reference is a better choice).

  • KnowMore

    It gives me an error of redefinition, Why?
    But, When I use

    inside of main() or if I delete the whole function, It works as expected!

    Is it that you have to actually omit the whole function and then use the delete keyword on its PROTOTYPE(eg. MyString(int) = delete;) and if you don't want to erase the function, you can delete it for some specific functions(like, delete operator<< for only main())
    Thanks In Advance !

    • Alex

      Two things:
      1) A function can only be deleted at the point where it is first declared. That means it has to happen inside the class definition, not outside the class.
      2) You're getting a redefinition error because you've supplied two different versions of the same function with the same signature.

  • susenj

    What is the point of leaving a function with 'delete' when it has not to be used anywhere? In my opinion, just omit that line and it will be equivalent. Or, am I missing something here?

    • Alex

      The compiler will provide some functions by default if you do not provide them yourself (e.g. a copy constructor). This gives you a way to tell the compiler that you not only don't want the provided function, but that any calls to such a function should be flagged as an error.

  • Miko

    Are these operator overloads correctly made?

    Visual studio doesn't seem to care about them so I can't test them. I tried to delete this, but code still returns what it is wanted to return.

  • Pawel

    Hi Alex,
    In the example where you use 'explicit' keyword for the first time, why do we get the compile error in the following line:

    I was expecting that the compiler will try to convert 5 to a MyString, which will invoke the MyString(int x) constructor. As far as I understand, the explicit keyword requires that the int is passed, so that e.g. char is not allowed. Since we're initializing the x object with 5 (which is int), I'd expect we have a match. Could you please clarify this?

    • Alex

      Sure. Explicit means the constructor will not be used to do implicit conversions. In the code:

      Because 5 is an int and x is a MyString, the compiler will have to convert the int to a MyString. Because we haven't requested an explicit conversion (e.g. via static_cast), the compiler will try to do an implicit conversion. Normally, it would be successful at this, because there is a MyString(int) constructor that it can use to convert an int into a MyString. However, in this case, because this constructor is marked as explicit, the compiler will exclude it for consideration when doing implicit conversions. Since the compiler won't find any other ways to implicitly convert an int to a MyString, it will give a compile error indicating that it doesn't know how to do the conversion.

      So, to conclude: explicit means the function will not be used for implicit conversion, but can still be used for explicit conversions.

  • loveu

    hi alex!
    why is the parameter of the constructor a char pointer?

  • Bobix Louis

    Hi Alex,
      A small doubt regarding the below behavior
      'However, note that making a constructor explicit only prevents implicit conversions. Explicit conversions (via direct or uniform initialization or explicit casts) are still allowed'

      Could you please help me to understand how it works? I mean, since we dont have any constructor that takes a char const(and the constructor that takes 'int' is already marked as explicit), how the creation of object is possible with direct or uniform initialization?

    • Alex

      I've updated the example a little bit to clarify better. Making a constructor only prevents implicit conversions. Explicit conversions (via casting) are allowed. Also, if you're creating an object, the parameters passed to that object may still be converted (subject to the usual constraints, such as uniform initialization won't do narrowing conversions).

      The compiler will happily let us do this:

      Because this isn't an implicit conversion of a value to a MyString (which is disallowed) -- it's an implicit conversion of char value 'x' to an integer, which is fine.

  • Jeffry

    HI again,  Very small thing.  I hope you don't mind the nit-pick.   In the first example can you either add a blank line before  lines 27 and 28 or bring them out to the same indentation as line 26.   At first glance it looked like lines 26 and 27 were the body of line 26, and it was confusing.   Then I looked at line 26 and realized there was a ; at the end and no { } so then understood what was going on.  But again at first glance it didn't seem that way.

    Thanks again for these pages, they are very helpful.

  • robbe

    Hey alex! When working with header files, where do I put the explicit keyword: in the forward declaration, the definition or both? Thanks in advance.

    • Alex

      Explicit only works with member functions, and member functions are part of classes, which don't need forward declarations (since the definition in the class serves as the definition).

      So just put the keyword explicit inside your class definition in your header file, and you should be good to go.

  • Ramesh

    Hi Alex
    In the first program of this tutorial, i thought copy constructor is called 2 times. once at copy initialization of 6 to makenegative parameter and one more time at returning by value from makenegative function.  
    So, the statement "Copy constructor called" should be printed twice.
    But it seems copy constructor is called only once. Is my understanding wrong?

    • Alex

      Nope. When literal 6 is passed as an argument to function makeNegative, the Fraction(int, int) constructor is used to copy-initialize f directly. No copy constructor used here.

      My wording in the lesson was a little confusing on this point, so I've updated it to the following:

      "Although function makeNegative() is expecting a Fraction, we've given it the integer literal 6 instead. Because Fraction has a constructor willing to take a single integer, the compiler will implicitly convert the literal 6 into a Fraction object. It does this by copy-initializing makeNegative() parameter f using the Fraction(int, int) constructor."

      The return value is still copy-constructed back to main().

      • Hi Alex,

        >> It does this by copy-initializing parameter f... (Shouldn't this be direct-initializing parameter f instead of copy-initializing?)

        I think the confusion here stems from the fact that people expect copy-initializing to invoke the copy constructor.

        Isn't that so? What is the difference between copy-constructing and copy-initializing? I thought the copy constructor would be invoked in both cases. So like the above commenter, I too am slightly puzzled why the copy constructor hasn't been called twice.

        Sorry, I know it's exhausting to clarify everyone. I'll understand if I don't hear from you :)


        • Alex

          Yes, I misspoke, you're correct in that it is doing a direct initialization, not a copy initialization.

          Copy initialization is used to construct a new object of type T, invoked through syntax of the form "T var = value". If value is an object of type T, a copy constructor will be invoked (assuming it exists) to create the object. If value is not of type T, some other non-copy constructor will be used (again, assuming an appropriate one exists).

  • dazedbrain

    typo found

    Constructors eligible to be used for implicit conversations are called converting constructors (or conversion constructors).

    do you mean implicit conversions?

  • Chris

    Hi Alex,

    at the section "The delete keyword" section you say "In our MyString case, we really want to completely disallow ‘x’ from being converted to a string (whether implicit or explicit, since the results aren’t going to be intuitive)."
    do you mean converted to an integer? since char is family integer and cannot be converted to string, i guess.

  • Sam

    I think Your explanation isn't fully correct in the first example. Output is the following:
    Copy constructor called
    After looking through the debugger (I might be wrong):
    1. Because there's a default constructor that "matches literal 6" the function call is allowed.
    2. Right after jumping to the function, default constructor is called. "f" has just been directly initialized.
    3. Copy constructor is called on the "return" statement, to evaluate it and pass back to "main" function. This anonymous object uses its overloaded operator to print its meaning.

  • Darren

    Is having the delete syntax for constructors a new(ish) thing added to c++11 (or later)? I've never seen it before. So instead of making the copy constructor and copy assignment operator private and not implementing them to make a class un-copyable (non-copyable?) you could just use the delete syntax instead? That is definitely more readable.

  • davidv

    Here's a silly question.
    If we add the prototypes for the copy constructor and overloaded operator= to the private section of the class in order to prevent copying, do we actually need to write them down later, given that we're not really planning to use them?

    • By write them down, I presume you mean implement them. The answer is no, as long as you don't call them. Don't forget that private members can still be called by other members of the class, so you'll have to ensure you don't use them internally within the class. If you try to do so, you'll get a linker error.

      • kudleep

        Hi Alex,

        can you give an example , how and in which case , one would need to use copy constructor from other class such as derived one ! The statement - "Sometimes we simply don’t want our classes to be copied at all." , can you please explain a bit, what i understood is we don't want compiler to provide a default copy constructor for our program.

        • I'm not sure what you mean by using copy constructors from other classes. The copy constructor is used to instantiate an object of a particular class, so the copy constructor for that class should always be used.

          As for not wanting your classes to be copied, sometimes there are legitimate reasons for this -- eg. doing an assignment would be too expensive, or you simply don't have time to implement a deep copy and want to prevent people from accidentally using the shallow copy provided by the default copy constructor and default assignment operator the compiler provides for all classes. By making these private, we tell the compiler not to create default versions, thus circumventing the issue.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]