0

I am learning C++ using the resources listed here. In particular, I came to know that copy initialization is used when passing arguments to function parameters(by value) etc.

For example, from decl.init.general#14:

The initialization that occurs in the = form of a brace-or-equal-initializer or condition ([stmt.select]), as well as in argument passing, function return, throwing an exception ([except.throw]), handling an exception ([except.handle]), and aggregate member initialization ([dcl.init.aggr]), is called copy-initialization.

(emphasis mine)

My question is that is there is reason for using copy initialization instead of direct initialization when passing argument to function parameters(by value)?


To make the question more concise, lets look at a contrived example:

struct C 
{
    explicit C(int)
    {
        
    }
};
void func(C param)
{
    
}

int main()
{
    C s1(2);  //#1: this works, direct-initialization and so explicit ctor can be used 
    C s2 = 2; //#2: won't work, copy-initialization and so explict ctor cannot be used here
    
    func(2);                  //#3:  won't work, copy-initialization of parameter param and so explict ctor cannot be used here
    return 0;
}

As we can see in the above example, the function call func(2) won't work because here the parameter param is copy initialized instead of direct initialized and so the explicit constructor C::C(int) cannot be used.

Summary

My question is why does the C++ standard(committee) choose to copy initialize the parameter param instead of direct initializing the parameter using the passed argument 2. I mean if param was direct initialized then the call func(2) would've succeeded.

Maybe there is a reason, like advantages of using copy initializing the parameter instead of direct initializing it or maybe there are disadvantages of using direct initializing the parameter instead of copy initializing it.

Jason
  • 36,170
  • 5
  • 26
  • 60
Kal
  • 475
  • 1
  • 16
  • 2
    This allows you to introduce conversion constructors that have to be used "on purpose". If the parameter was a class that acquires a number of expensive resources and the user was under the impression that there was an overload taking `int` doing something a bit different, then not being able to prevent this conversion from automatically happening wouldn't be good... You can still call the function without introducing an additional object using `func(C(2))` because of copy elision... – fabian Aug 10 '22 at 16:44
  • 1
    The whole point of `explicit` is to make it so that such an initialization/conversion doesn't happen automatically without clearly stating to which type the argument is converted. If you changed the rule so that function arguments direct-initialize the parameter, what would you expect `explicit` to be good for? – user17732522 Aug 10 '22 at 17:18
  • @fabian: should be an answer not a comment – Tony Delroy Aug 10 '22 at 17:21
  • Your post sounds like you think there's some kind of penalty for using copy-init, other than banning certain constructors from being called. – HolyBlackCat Aug 10 '22 at 17:55

1 Answers1

4

It is precisely so that this does not work.

The whole point of the distinction between copy-initialization and direct-initialization is to prevent implicit conversions in cases of copy-initialization. By using explicit in your constructor, you are declaring that you do not want integers to be converted to C unless the user spells it out directly.

When you attempt to call func(2), the type C is not explicitly visible anywhere near the call site. Therefore, it should be copy-initialization and if C's conversion constructor from int is explicit, the call should be disallowed.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982