initialisation list in constructor

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Taras_96

    initialisation list in constructor

    Hi everyone,

    The FAQ at http://www.parashift.com/c++-faq-lit....html#faq-10.6
    states that:

    "Consider the following constructor that initializes member object x_
    using an initialization list: Fred::Fred() : x_(whatever) { }. The
    most common benefit of doing this is improved performance. For
    example, if the expression whatever is the same type as member
    variable x_, the result of the whatever expression is constructed
    directly inside x_ — the compiler does not make a separate copy of the
    object. Even if the types are not the same, the compiler is usually
    able to do a better job with initialization lists than with
    assignments.

    The other (inefficient) way to build constructors is via assignment,
    such as: Fred::Fred() { x_ = whatever; }. In this case the expression
    whatever causes a separate, temporary object to be created, and this
    temporary object is passed into the x_ object's assignment operator.
    Then that temporary object is destructed at the ;. That's inefficient.

    As if that wasn't bad enough, there's another source of inefficiency
    when using assignment in a constructor: the member object will get
    fully constructed by its default constructor, and this might, for
    example, allocate some default amount of memory or open some default
    file. All this work could be for naught if the whatever expression and/
    or assignment operator causes the object to close that file and/or
    release that memory (e.g., if the default constructor didn't allocate
    a large enough pool of memory or if it opened the wrong file). "

    I believe that if you write Fred::Fred() {x_ = whatever;} then
    effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
    whatever;}. This is what I think the last paragraph is saying (the
    member object will get fully constructed by it's default constructor).

    However, I don't see what the second paragraph is saying. If whatever
    is a primitive, then no 'temporary object' will be created. If
    whatever is an object, then a temporary object would have to be
    created anyway in the initialisation example anyway:

    Fred::Fred(): x_(WhateverClas s()) {}

    When is the temporary copy being referred to created?

    in a 'normal function':

    if we write:

    Foo foo = bar;

    then whether a temporary Bar object is created depends on the
    definition of the Foo constructor:

    Foo(Bar &); // no copy made
    Foo(Bar); // copy made

    Taras
  • Salt_Peter

    #2
    Re: initialisation list in constructor

    On Oct 23, 7:25 pm, Taras_96 <taras...@gmail .comwrote:
    Hi everyone,
    >
    The FAQ athttp://www.parashift.c om/c++-faq-lite/ctors.html#faq-10.6
    states that:
    >
    "Consider the following constructor that initializes member object x_
    using an initialization list: Fred::Fred() : x_(whatever) { }. The
    most common benefit of doing this is improved performance. For
    example, if the expression whatever is the same type as member
    variable x_, the result of the whatever expression is constructed
    directly inside x_ — the compiler does not make a separate copy of the
    object. Even if the types are not the same, the compiler is usually
    able to do a better job with initialization lists than with
    assignments.
    >
    The other (inefficient) way to build constructors is via assignment,
    such as: Fred::Fred() { x_ = whatever; }. In this case the expression
    whatever causes a separate, temporary object to be created, and this
    temporary object is passed into the x_ object's assignment operator.
    Then that temporary object is destructed at the ;. That's inefficient.
    >
    As if that wasn't bad enough, there's another source of inefficiency
    when using assignment in a constructor: the member object will get
    fully constructed by its default constructor, and this might, for
    example, allocate some default amount of memory or open some default
    file. All this work could be for naught if the whatever expression and/
    or assignment operator causes the object to close that file and/or
    release that memory (e.g., if the default constructor didn't allocate
    a large enough pool of memory or if it opened the wrong file). "
    >
    I believe that if you write Fred::Fred() {x_ = whatever;} then
    effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
    whatever;}. This is what I think the last paragraph is saying (the
    member object will get fully constructed by it's default constructor).
    >
    However, I don't see what the second paragraph is saying. If whatever
    is a primitive, then no 'temporary object' will be created. If
    whatever is an object, then a temporary object would have to be
    created anyway in the initialisation example anyway:
    >
    Fred::Fred(): x_(WhateverClas s()) {}
    >
    When is the temporary copy being referred to created?
    If you assign x_ in the ctor body instead of the init list, Fred's
    ctor needs to allocate its members at the very least. This happens
    before the ctor's body is processed.

    ....in the same breath ...
    int temp(0);
    int m = temp; // is a copy

    note the difference now:
    int temp(0);
    int m;
    m = temp; // is not a copy. assignment

    The difference is that the first set of statements can be optimized
    away, the assignment usually cannot.
    >
    in a 'normal function':
    >
    if we write:
    >
    Foo foo = bar;
    >
    then whether a temporary Bar object is created depends on the
    definition of the Foo constructor:
    >
    Foo(Bar &); // no copy made
    Foo(Bar); // copy made
    >
    Taras
    Whether a temporary is created depends on whether its creation can be
    optimized away or not.
    In your second example, Foo(Bar); you'ld get 2 copies if it wasn't
    optimized and you did use the init list (a temp is generated), 2
    copies + op= if you didn't use the init list. In the first example
    you'ld get a copy unless you were setting a member reference (no
    temporary). Fortunately, that copy is usually optimized away.

    For all intensive purposes, those paragraphs in faq-10.6 are relevent
    since they give an overview of the difference between using the init
    list and assignments. In reality the ctor, at the very least, will
    allocate / reserve memory for its members before its body is
    processed. Why not initialize those members using the init list then?

    Copies are very fast usually. The same can't be said of allocation +
    assignment.
    Consider that most op= include an a self assignment check:

    [http://www.parashift.com/c++-faq-lit...perators.html]

    Fred& Fred::operator= (const Fred& f)
    {
    if (this == &f) return *this; // Gracefully handle self
    assignment

    // Put the normal assignment duties here...

    return *this;
    }

    There is no reason not to use the init list. For a programmer: its
    often a blessing. Take for example a simple way to zap the unitialized
    pointer issue:

    class P
    {
    int* p;
    public:
    P() : p(0) { }
    ...
    };

    The init list is more than just about efficiency.

    Comment

    • Victor Bazarov

      #3
      Re: initialisation list in constructor

      Taras_96 wrote:
      [..]
      I believe that if you write Fred::Fred() {x_ = whatever;} then
      effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
      whatever;}. This is what I think the last paragraph is saying (the
      member object will get fully constructed by it's default constructor).
      Actually, it's more like

      Fred::Fred() : x_() { x_ = whatever; }

      'x_' is default-initialised before being assigned to.
      However, I don't see what the second paragraph is saying. If [..]
      You're basing your conclusions on a wrong premise, I'm afraid.
      in a 'normal function':
      >
      if we write:
      >
      Foo foo = bar;
      >
      then whether a temporary Bar object is created depends on the
      definition of the Foo constructor:
      >
      Foo(Bar &); // no copy made
      Foo(Bar); // copy made
      No. By definition, the form

      TypeA objA = objB;

      is a shorthand for

      TypeA objA((TypeA(obj B)));

      The syntax with the '=' is *not* direct initialisation, it is
      copy-intialisation from a *temporary object*, which is in turn
      directly initialised from 'objB'.

      In reality the compiler most likely skips the temporary and makes
      the code analogous to

      TypeA objA(objB);

      but the difference is that the copy constructor in 'TypeA' *must*
      exist and be accessible. That's the requirement.

      V
      --
      Please remove capital 'A's when replying by e-mail
      I do not respond to top-posted replies, please don't ask

      Comment

      • blargg

        #4
        Re: initialisation list in constructor

        In article <gdr5ep$gg0$1@n ews.datemas.de> , Victor Bazarov
        <v.Abazarov@com Acast.netwrote:
        Taras_96 wrote:
        [..]
        I believe that if you write Fred::Fred() {x_ = whatever;} then
        effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
        whatever;}. This is what I think the last paragraph is saying (the
        member object will get fully constructed by it's default constructor).
        >
        Actually, it's more like
        >
        Fred::Fred() : x_() { x_ = whatever; }
        >
        'x_' is default-initialised before being assigned to.
        [...]

        ....unless x_ is a built-in or POD type, in which case it has an
        indeterminate value on entry to the constructor, before the assignment.

        Comment

        • Ian Collins

          #5
          Re: initialisation list in constructor

          blargg wrote:
          In article <gdr5ep$gg0$1@n ews.datemas.de> , Victor Bazarov
          <v.Abazarov@com Acast.netwrote:
          >
          >Taras_96 wrote:
          >>[..]
          >>I believe that if you write Fred::Fred() {x_ = whatever;} then
          >>effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
          >>whatever;}. This is what I think the last paragraph is saying (the
          >>member object will get fully constructed by it's default constructor).
          >Actually, it's more like
          >>
          > Fred::Fred() : x_() { x_ = whatever; }
          >>
          >'x_' is default-initialised before being assigned to.
          [...]
          >
          ....unless x_ is a built-in or POD type, in which case it has an
          indeterminate value on entry to the constructor, before the assignment.
          No, x_() default initialises it.

          --
          Ian Collins

          Comment

          • blargg

            #6
            Re: initialisation list in constructor

            In article <6mcs5rFg531aU1 0@mid.individua l.net>, Ian Collins
            <ian-news@hotmail.co mwrote:
            blargg wrote:
            In article <gdr5ep$gg0$1@n ews.datemas.de> , Victor Bazarov
            <v.Abazarov@com Acast.netwrote:
            Taras_96 wrote:
            >[..]
            >I believe that if you write Fred::Fred() {x_ = whatever;} then
            >effectively what you're getting is Fred::Fred(): x_(whatever) {x_ =
            >whatever;}. This is what I think the last paragraph is saying (the
            >member object will get fully constructed by it's default constructor).
            Actually, it's more like
            >
            Fred::Fred() : x_() { x_ = whatever; }
            >
            'x_' is default-initialised before being assigned to.
            [...]

            ....unless x_ is a built-in or POD type, in which case it has an
            indeterminate value on entry to the constructor, before the assignment.
            >
            No, x_() default initialises it.
            Sorry, I was referring to Taras_96's original example,

            Fred::Fred() {x_ = whatever;}

            noting that it is NOT exactly equivalent to Victor Bazarov's example,

            Fred::Fred() : x_() { x_ = whatever; }

            when x_ is a built-in or POD type. The difference would be hard to detect
            in this case since x_ is immediately assigned a value.

            Comment

            • James Kanze

              #7
              Re: initialisation list in constructor

              On Oct 24, 1:25 am, Taras_96 <taras...@gmail .comwrote:
              The FAQ
              athttp://www.parashift.c om/c++-faq-lite/ctors.html#faq-10.6
              states that:
              "Consider the following constructor that initializes member object x_
              using an initialization list: Fred::Fred() : x_(whatever) { }. The
              most common benefit of doing this is improved performance.
              I'm going to disagree with the FAQ on this one. It's true that
              doing so may result in improved performance, but that is rarely
              the main motivation, or even a motivation. The most common
              benefit of doing this is that it is cleaner; that you don't have
              to worry about uninitialized or incorrectly initialized
              variables in the body of your constructor. The general rule is
              to never declare a variable without initializing it; member
              variables are implicitlly declared before entering the
              constructor, so logically, you want to initialize them before
              entering the constructor.

              Another frequent reason is that the type may not have a default
              constructor (a lot of my types don't), so you have to initialize
              it in the initializer list; otherwise, you get an error.

              --
              James Kanze (GABI Software) email:james.kan ze@gmail.com
              Conseils en informatique orientée objet/
              Beratung in objektorientier ter Datenverarbeitu ng
              9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

              Comment

              Working...