initialization of function argument

Discussion in 'C++' started by subramanian100in, Nov 25, 2007.

  1. Suppose we have a class named Test.

    Test obj; // assuming default ctor is available
    Test direct_init(obj); // direct initialization happens here
    Test copy_init = obj; // copy initialization happens here

    Suppose we have a function

    void fn(Test arg);

    When we call fn() with fn(obj), the copy ctor
    is called to construct 'arg'. Am I correct?
    Question is what kind of initialization - direct
    initialization or copy initialization, happens to
    construct arg ?
    What does the standard say in this regard ?
    If copy initialization happens, then if the copy
    ctor is 'explicit', then calling fn(obj) will not
    compile. Am I correct ?

    Kindly explain

    subramanian100in, Nov 25, 2007
    1. Advertisements

  2. * , India:
    Formally it's copy initializion, per §8.5/12.

    Try submitting the following code to Comeau Online,

    struct Foo
    explicit Foo( Foo const& ) {}

    void bar( Foo ) {}

    int main()
    bar( Foo() );

    Cheers, & hth.,

    - Alf
    Alf P. Steinbach, Nov 25, 2007
    1. Advertisements

  3. subramanian100in

    Mike Wahler Guest

    I'm not sure what you mean by 'direct initialization', but
    the above line invokes the copy constructor.
    This will also invoke the copy constructor.
    Copy construction.
    I don't have my copy at hand.
    Sure it will.

    However, if the copy constructor is declared explicit,
    the line

    Test copy_init = obj;

    will not compile. (VC++ 2005 says:
    class 'Test' : no copy constructor available or
    copy constructor is declared 'explicit'

    Run my example below.

    #include <iostream>

    class Test
    static int i;

    std::cout << "Obj " << i << " Default constructor\n";

    Test(const Test& t)
    std::cout << "Obj " << i << " Copy constructor\n";

    Test& operator=(const Test& t)
    std::cout << std::cout << "Obj " << i << " Assignment operator\n";
    return *this;


    std::cout << "Obj " << i << " destructor\n";

    int Test::i;

    void fn(Test arg)

    int main()
    Test obj;
    Test direct_init(obj);
    Test copy_init = obj;
    std::cout << "Before calling fn\n";
    std::cout << "After fn()\n";
    return 0;


    Obj 1 Default constructor
    Obj 2 Copy constructor
    Obj 3 Copy constructor
    Before calling fn
    Obj 4 Copy constructor
    Obj 4 destructor
    After fn()
    Obj 3 destructor
    Obj 2 destructor
    Obj 1 destructor

    Mike Wahler, Nov 25, 2007
  4. * Mike Wahler:
    See my reply about two hours earlier in this thread. It's often a good
    idea to read earlier replies in the thread, before posting.

    I'm sorry, it will only compile with a broken compiler (e.g. MSVC).

    He is correct.

    When I added the word "explicit" to the copy constructor of your
    program, and commented out the copy_init declaration,

    Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
    Copyright 1988-2007 Comeau Computing. All rights reserved.
    MODE:strict errors C++ C++0x_extensions

    "ComeauTest.c", line 47: error: class "Test" has no suitable copy

    1 error detected in the compilation of "ComeauTest.c".

    g++ also failed to compile, whereas Visual C++ did compile it.

    So we can conclude that of the three compilers I tested your code with,
    one did not handle the "explicit" copy constructor correctly.

    Cheers, & hth.,

    - Alf
    Alf P. Steinbach, Nov 25, 2007
  5. You should check which flags you are using then, I could not get that
    past the VC++ compiler.
    Erik Wikström, Nov 25, 2007
  6. Those lines do the exact same thing. The latter is just syntactic
    sugar for the former.
    Juha Nieminen, Nov 25, 2007
  7. * Juha Nieminen:
    I'm sorry, that's incorrect.

    Try reading the posting you replied to to pick up relevant terms.

    Read the rest of the thread for discussion and more information (it's
    often a good idea to read the articles in a thread before contributing).

    Cheers, & hth.,

    - Alf
    Alf P. Steinbach, Nov 25, 2007
  8. Does this mean that making the copy constructor of the class explicit
    is an effective way of prohibiting objects of that type from being
    passed to functions by value?

    If this is so, then calling bar() is basically impossible?
    Juha Nieminen, Nov 25, 2007
  9. subramanian100in

    James Kanze Guest

    Not if Test is a class type and obj has a type other than Test.
    In that case, the first says to construct a Test with obj, the
    second to convert obj to a Test, and construct a Test with the
    results of the conversion. In the first, there is no
    conversion, so constructors marked explicit can be used, but
    conversion operators in the source type can't be), and no copy,
    so it is legal even if Test doesn't have an accessible copy
    constructor. In the second, there is conversion, so
    constructors marked explicit cannot be used, but conversion
    operators in the source type can be, and copy, so an accessible
    copy constructor must be available.

    If obj is of type Test, of course, or a class derived from Test
    (ignoring any const or volatile qualifiers), then copy
    initialization is defined to have the same behavior as direct
    initialization. (It's not really clear if the copy constructor
    is declared explicit, of course---the standard contradicts
    itself in that case, saying elsewhere that the direct
    initialization syntax cannot be used if the constructor is
    declared explicit.)
    James Kanze, Nov 26, 2007
  10. subramanian100in

    James Kanze Guest

    Formally, it's copy initialization. But the standard also says
    that if the type of the initialization is the same as, or a
    class derived from, the target type, copy initialization behaves
    the same as direct initialization. There is only a difference
    when conversions are involved.
    Exactly what I just said.
    I don't think so, but the original standard is far from clear.
    In the section on initialization, it makes it very clear that if
    the initialization expression in copy initialization has the
    same type as, or a type derived from, the target type, the
    semantics are the same as those of direct initialization. In
    the section concerning explicit, on the other hand, the latest
    draft says that an explicit constructor will only be used "where
    the direct-initialization syntax (8.5) or where casts (5.2.9,
    5.4) are explicitly used." (Of course, it contradicts this for
    explicit default constructors in the very next sentence. But
    that doesn't affect the copy constructor.)

    The simplest solution is just to never declare the copy
    constructor explicit. (Since explicit is designed to prevent
    conversions, and the copy constructor doesn't "convert" anything
    in the classical sense of the word, the logical decision would
    have been for explicit to be ignored on the copy constructor.)
    James Kanze, Nov 26, 2007
  11. subramanian100in

    James Kanze Guest

    Also, perhaps, the version. I think that there was some
    discussion concerning what was really meant in the standards
    committee; the standard does contradict itself on this subject,
    and it's quite possible that compiler implementors interpreted
    it differently at one time.
    James Kanze, Nov 26, 2007
  12. * James Kanze:
    This is also the language of the original standard.

    It's not a contradiction: "explicit" is a limitation on allowable syntax
    for constructor calls, namely that they must be explicit, and is not
    concerned with the final semantic effect of a call.

    In other words, §8.5 on initialization refers to the semantic effect,
    whereas §12.3.1 on explicit constructors refers to which syntax syntax
    is allowed.

    Only in the cases where explicit constructor call syntax is not
    available (the only such case I know is passing an argument by value)
    does that limit what can be done, the possible semantics.

    I'm not sure I understand what you mean here or really what you're
    referring to. Possibly you're talking about the exception for default
    constructors. If so then yes I agree the wording is not very clear.

    But no matter. :)

    That would introduce another special case (in addition to the default
    constructor), and this time on the argument type. Which would either be
    inconsistent with effect of -- I'm assuming this is allowed --

    template< class T >
    explicit MyClass( T const & );

    or make this templated non-copy constructor allow different call
    /syntax/ dependending on the actual argument /type/.

    It's messy. I think perhaps the decision to mix construction and
    conversion in one common syntax was not optimal, because it places the
    decision of whether you want implicit conversion in one central place,
    namely in the class definition. Instead, that decision may conceivably
    better be expressed at each place a conversion would put its result,
    with no implicit conversion as default. However, I'm not sure. It's
    difficult to say without experience with a language that does this.

    Cheers, & hth.,

    - Alf
    Alf P. Steinbach, Nov 26, 2007
  13. Hello Alf P. Steinbach,

    I got clarified with your answer in comp.lang.c++ for the same
    question. I thank you for that.
    But I had sent this question to comp.std.c++ three days
    ago. Since I didn't get the question posted in
    comp.std.c++, I thought it got rejected by the moderator
    in comp.std.c++. So I posted the same question in

    I regret if I caused any inconvenience to you.

    Hope this clarifies.

    subramanian100in, Nov 27, 2007
  14. subramanian100in

    James Kanze Guest

    That does sound like the most reasonable interpretation. (Of
    what is written, not of what should be specified.)
    There is no such thing as an "explicit constructor call syntax".
    Or are you using this as a synonym for "direct-initialization
    syntax or casts"?

    At any rate, another case would be return values, and I think
    some cases involved in exceptions (catching by value, certainly,
    but what about the copy which takes place during a throw?).

    Yup. More than I realized at first glance. On the other hand,
    it would allow the simple rule of always declaring constructors
    explicit, without worrying about whether they might be used for
    copy or not.

    Your template example suggests an even more pernitious example
    to me:

    class Toto
    Toto( Toto& other ) ;
    template< typename T >
    explicit Toto( T const& other ) ;
    } ;

    void f( Toto ) ;

    Toto t1 ;
    Toto const t2 ;
    f( t1 ) ; // no problem...
    f( t2 ) ; // illegal! even though a copy is passed.

    Off hand, I'd say that your example with the template is even
    more of an argument that something isn't right. That explicit
    should probably only have an effect when an implicit conversion
    is involved, and should be ignored otherwise. (But I'm not sure
    how to express that in standardese.)
    I think that there's more or less general agreement about this
    now. It's a historical issue.
    James Kanze, Nov 27, 2007
  15. Apparently nobody knows.
    Juha Nieminen, Nov 27, 2007
  16. I know.

    Yes, it is impossible. The absence of the default c-tor in 'Foo'
    makes it impossible to create an instance of 'Foo' to begin the
    copying process. And it has nothing to do with the fact that the
    copy-c-tor is declared 'explicit'.

    Victor Bazarov, Nov 27, 2007
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.