13.14 — Converting constructors, explicit, and delete

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

Although function printFraction() 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 printFraction() parameter f using the Fraction(int, int) constructor.

Consequently, the above program prints:


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. Similarly, a call to printString(‘x’) causes an implicit conversion that results in the same issue.

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 function’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

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.

13.15 -- Overloading the assignment operator
13.13 -- Copy initialization

118 comments to 13.14 — Converting constructors, explicit, and delete

  • Lilakuh


    Regarding the explicit MyString constructor:


    basically seen as

    by the compiler? Shouldn't this code still compile, since uniform initialization will still convert 'x' to match the MyString(int) constructor?

    Could one say, in most cases the copy constructor is NOT called for something like


    • nascardriver

      > Could one say, in most cases the copy constructor is NOT called for something like
      The copy constructor is only called if you have an existing object and create a new object with the old object as an argument. Temporaries don't count as objects in this case.

      Explicit constructors only disallow copy initialization. It's not useful for this kind of copy initialization

      That's illegal, but that's not where `explicit` is useful.
      The important part is that copy initialization is used to initialize function parameters. When you have a function like

      You can't call it without explicitly calling the constructor of `MyString`

      `str` is initialized with copy initialization, and the `explicit` makes the constructor call illegal. You have to use a `MyString`.

      With `MyString`, we don't really need an `explicit` constructor for `char`s. It's obvious that 'x' will be a string. But take `std::vector` for example, it has a constructor that takes an integer (The initial size of the vector).

  • joe

    Hi, I have a few questions:

    1.Why are the parameters const if it doesnt take references? won't the array be copied?
    2.For the string constructor, why is this used

    instead of this?

    • Alex

      1) No, it won't be copied, because it's a pass by address. Only the address is copied, not the entire array.
      2) Because the example uses C-style strings, not C++ style strings. If this were a non-contrived example, it would make sense to use std::string_view so as not to make an unnecessary copy of the string parameter.

  • Daniel

    I want to return object of class Cents in function like this

    If I declare my constructor as explicit, this won't work. How can I make it work? Is there some other way aside from just making temporary object and then return it? Because if I also had my copy constructor denoted as explicit, then this workaround wouldn't work.

  • Anastasia

    In the paragraph 'The explicit keyword' the function `printString()` is missing in the 2d code example (only call to it in `main()` is present).

  • Aszriel

    Hello I have a question :

    Why would you use this line :

    if the function is supposed to wait a Fraction ?

    Also why would you use copy initialization like this :

    if you can use constructor with direct initialization like this :

    I do not know if my question is clear ? I hope so

    Thanks in advance

    • Alex

      1) I updated the example to show a case that better illustrates why you might want to do this. printFraction(6) works the same as printFraction(Fraction(6)), but it's shorter and doesn't lose much comprehensibility.

      2) I also updated this example. Using the explicit keyword won't save you if you're doing direct/uniform initialization, but it will still prevent implicit conversions from happening when calling functions. The updated example shows this.

  • Hadi

    Hello Alex
    isn't better to write :

    instead of

    because it causes a lot of confusion
    or there is something i don't understand.....

    • Alex

      You're talking about where to put the asterisk (e.g. with the type or the name?)

      It ultimately doesn't matter, and there are good reasons to prefer/justify either way.

  • 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.

      • hellmet

        This is pretty unintuitive.

        So, only in cases where the constructor is explicitly called (as is writing out the constructor with arguments), implicit casting cannot occur for an 'explicit' marked constructor. The reason why {} or copy work is because they do some inside 'magic' to desperately match _any_ constructor, and then call the correct constructor, correct? This way, the constructor gets the argument it expects and creates the object.

        If so, seems like a reason to stay away from uniform init for class objects.

        • nascardriver

          I don't use `explicit`, but I want to share my thoughts anyway.

          `v1`: We're using a list constructor to initialize a list type. Our intuition says that the vector now has 1 element, a 5. That's correct.

          `v2`: We're using direct initialization (Syntax of a function call). Our intuition says that we're calling a constructor (5 elements, each 0). That's correct.

          `v3`: Well what's this supposed to do? My intuition at least doesn't help. The constructor is `explicit`, which makes `v3` illegal. That's good imo.

          Also note that parameters are initialized via copy-initialization.

          Now that I though about it a little, maybe I should start using `explicit`...

          • Alex

   advises doing this for single-argument constructors, to prevent unintended implicit conversions.

            • hellmet

              Hmmm yes, that makes a lot of sense.

              Perhaps being more vigilant to the expectations of what a caller wants to do is the best way to make sure intended results occur, while not taking away from the ease of using uniform init... and of course, using explicit to prevent surprises where they might occur.

              Also, how would I disambiguate the constructors of the following? Are these used (in comments)?

              The explicit just prevents copy initialization with the wrong parameter, correct (say an int/decimal etc..)? The = here best makes sense when used to copy one vector to another, hence the explicit to prevent ambiguous (to the user) usages. How is 5 still converted from int to size_type then? Shouldn't the second call be

              I was thinking "oh perhaps an implicit cast int -> size_type exists" but that's stupid cause that's the whole point of explicit, to prevent implicit casts!

              Also also, in

              the 5 is an int anyway, why would I need to cast? I think a a

              was intended here?

              • nascardriver

                > Are these used (in comments)?
                Yes, those are the correct constructors.

                > The explicit just prevents copy initialization with the wrong parameter, correct (say an int/decimal etc..)?
                It prevents copy initialization with this constructor altogether.

                > How is 5 still converted from int to size_type then?
                It's used in direct initialization. Direct initialization isn't affected by `explicit`.

                > why would I need to cast?
                You don't, you could construct a `MyString` in-place: `MyString{ 5 }`. The point of that example is to show a cast, so I'll leave it as-is.

                • hellmet

                  > It prevents copy initialization with this constructor altogether.
                  Ahhhh! I see! Marking any constructor explicit does not allow copy initialization at all. Nice. This then looks for the copy constructor if it exists, or just fails! What about the default copy constructor? I'm assuming that works only for the same object type (i.e, T a = b works only if b is of type T).
                  A lot of things are clearer now! Thank you!

                  > You don't, you could construct a `MyString` in-place: `MyString{ 5 }`.
                  Oh I meant to say that there exists a direct constructor taking the exact parameters (i.e, an int), so a cast wouldn't be necessary. Perhaps a case where only a static_cast is the way to convert would be a more concrete example. Not to worry, the existing one is perfect as is, I thought better make the usage example more ... explicit :)

                  For example,

                  Thank you for the clarifications!

                  • nascardriver

                    > Perhaps a case where only a static_cast is the way to convert
                    Just like in the lesson, your `static_cast` can be replaced by a manual conversion by calling the constructor

                    > What about the default copy constructor?
                    Only the constructors marked as `explicit` aren't usable for copy-initialization. Other constructors are unaffected.
                    If you mark the copy constructor as `explicit`, you can't use it for copy initialization (`T b; T a = b;` is illegal).

                    • hellmet

                      > can be replaced by a manual conversion by calling the constructor
                      Ahhh! I get the point now! My apologies!

                      > you can't use it for copy initialization (`T b; T a = b;` is illegal)
                      Perfect! Makes sense now! So I'll just need to add that to the class, since not specifying a copy constructor uses a default one (as described in lesson 9.11).

                      Thank you so much for clearing all that up!

                  • nascardriver

                    > So I'll just need to add that to the class
                    That's bad though. You won't be able to use your type with copy-initialization. Function calls use copy initialization. You won't be able to use your type as a parameter.
                    I can't imagine a practical use for explicit copy constructors.

                    • hellmet

                      Right! I forgot about that :)

                      Perhaps cases where a single entity that remains through the lifetime of a program? Like a root window? So all parameters have to be const or normal references depending on what the function is doing...

                      Thank you!

  • 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]