Do the parentheses after the type name make a difference with new?

后端 未结 6 1066
余生分开走
余生分开走 2020-11-21 04:15

If \'Test\' is an ordinary class, is there any difference between:

Test* test = new Test;

and

Test* test = new Test();


        
相关标签:
6条回答
  • 2020-11-21 04:54

    new Thing(); is explicit that you want a constructor called whereas new Thing; is taken to imply you don't mind if the constructor isn't called.

    If used on a struct/class with a user-defined constructor, there is no difference. If called on a trivial struct/class (e.g. struct Thing { int i; };) then new Thing; is like malloc(sizeof(Thing)); whereas new Thing(); is like calloc(sizeof(Thing)); - it gets zero initialized.

    The gotcha lies in-between:

    struct Thingy {
      ~Thingy(); // No-longer a trivial class
      virtual WaxOn();
      int i;
    };
    

    The behavior of new Thingy; vs new Thingy(); in this case changed between C++98 and C++2003. See Michael Burr's explanation for how and why.

    0 讨论(0)
  • 2020-11-21 04:55

    In general we have default-initialization in first case and value-initialization in second case.

    For example: in case with int (POD type):

    • int* test = new int - we have any initialization and value of *test can be any.

    • int* test = new int() - *test will have 0 value.

    next behaviour depended from your type Test. We have defferent cases: Test have defult constructor, Test have generated default constructor, Test contain POD member, non POD member...

    0 讨论(0)
  • 2020-11-21 05:02

    The rules for new are analogous to what happens when you initialize an object with automatic storage duration (although, because of vexing parse, the syntax can be slightly different).

    If I say:

    int my_int; // default-initialize → indeterminate (non-class type)
    

    Then my_int has an indeterminate value, since it is a non-class type. Alternatively, I can value-initialize my_int (which, for non-class types, zero-initializes) like this:

    int my_int{}; // value-initialize → zero-initialize (non-class type)
    

    (Of course, I can't use () because that would be a function declaration, but int() works the same as int{} to construct a temporary.)

    Whereas, for class types:

    Thing my_thing; // default-initialize → default ctor (class type)
    Thing my_thing{}; // value-initialize → default-initialize → default ctor (class type)
    

    The default constructor is called to create a Thing, no exceptions.

    So, the rules are more or less:

    • Is it a class type?
      • YES: The default constructor is called, regardless of whether it is value-initialized (with {}) or default-initialized (without {}). (There is some additional prior zeroing behavior with value-initialization, but the default constructor is always given the final say.)
      • NO: Were {} used?
        • YES: The object is value-initialized, which, for non-class types, more or less just zero-initializes.
        • NO: The object is default-initialized, which, for non-class types, leaves it with an indeterminate value (it effectively isn't initialized).

    These rules translate precisely to new syntax, with the added rule that () can be substituted for {} because new is never parsed as a function declaration. So:

    int* my_new_int = new int; // default-initialize → indeterminate (non-class type)
    Thing* my_new_thing = new Thing; // default-initialize → default ctor (class type)
    int* my_new_zeroed_int = new int(); // value-initialize → zero-initialize (non-class type)
         my_new_zeroed_int = new int{}; // ditto
           my_new_thing = new Thing(); // value-initialize → default-initialize → default ctor (class type)
    

    (This answer incorporates conceptual changes in C++11 that the top answer currently does not; notably, a new scalar or POD instance that would end up an with indeterminate value is now technically now default-initialized (which, for POD types, technically calls a trivial default constructor). While this does not cause much practical change in behavior, it does simplify the rules somewhat.)

    0 讨论(0)
  • 2020-11-21 05:09

    Let's get pedantic, because there are differences that can actually affect your code's behavior. Much of the following is taken from comments made to an "Old New Thing" article.

    Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD (plain old data), or if it's a class that contains POD members and is using a compiler-generated default constructor.

    • In C++1998 there are 2 types of initialization: zero and default
    • In C++2003 a 3rd type of initialization, value initialization was added.

    Assume:

    struct A { int m; }; // POD
    struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
    struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m
    

    In a C++98 compiler, the following should occur:

    • new A - indeterminate value
    • new A() - zero-initialize

    • new B - default construct (B::m is uninitialized)

    • new B() - default construct (B::m is uninitialized)

    • new C - default construct (C::m is zero-initialized)

    • new C() - default construct (C::m is zero-initialized)

    In a C++03 conformant compiler, things should work like so:

    • new A - indeterminate value
    • new A() - value-initialize A, which is zero-initialization since it's a POD.

    • new B - default-initializes (leaves B::m uninitialized)

    • new B() - value-initializes B which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.

    • new C - default-initializes C, which calls the default ctor.

    • new C() - value-initializes C, which calls the default ctor.

    So in all versions of C++ there's a difference between new A and new A() because A is a POD.

    And there's a difference in behavior between C++98 and C++03 for the case new B().

    This is one of the dusty corners of C++ that can drive you crazy. When constructing an object, sometimes you want/need the parens, sometimes you absolutely cannot have them, and sometimes it doesn't matter.

    0 讨论(0)
  • 2020-11-21 05:11

    No, they are the same. But there is a difference between:

    Test t;      // create a Test called t
    

    and

    Test t();   // declare a function called t which returns a Test
    

    This is because of the basic C++ (and C) rule: If something can possibly be a declaration, then it is a declaration.

    Edit: Re the initialisation issues regarding POD and non-POD data, while I agree with everything that has been said, I would just like to point out that these issues only apply if the thing being new'd or otherwise constructed does not have a user-defined constructor. If there is such a constructor it will be used. For 99.99% of sensibly designed classes there will be such a constructor, and so the issues can be ignored.

    0 讨论(0)
  • 2020-11-21 05:18

    Assuming that Test is a class with a defined constructor, there's no difference. The latter form makes it a little clearer that Test's constructor is running, but that's about it.

    0 讨论(0)
提交回复
热议问题