Re: If there are many member variables in a class, how can Iinitialize them fast in the constructor?

Discussion in 'C++' started by Goran, Feb 17, 2011.

  1. Goran

    Goran Guest

    On Feb 17, 4:02 am, KaiWen <> wrote:
    > eg:
    > class SomeThing {
    > public:
    >         SomeThing();
    > private:
    >         a
    >         b
    >         c
    >         ...
    >         ...
    >         // a lot of variables
    >
    > };
    >
    > If this is not a derived class(there is no vptr), can I use
    > memset in constructor?


    In practice, yes, in theory, no. In theory, you can't do memset on
    anything but POD types, and current (not C++0x) POD type rules are
    quite strict (even a default ctor is out, which is IMO stupid).

    If you need that your stuff is zeroed out, here's a possible
    workaround:

    template<typename POD>
    POD ZeroedPOD()
    {
    POD result;
    memset(&result, 0, sizeof result);
    return result;
    }

    namespace SomeThingDetails
    {
    struct Members
    {
    TYPEa a;
    TYPEb b;
    //...
    TYPEx x;
    }
    };

    class SomeThing : SomeThingDetails::Members
    {
    SomeThing(params) :
    SomeThingDetails::Members(ZeroedPOD<SomeThingDetails::Members>())
    };

    ZeroedPOD gives you, a zeroed-out POD. Return value optimization and
    inlining during optimization (a rather safe, but not 100% safe, bet)
    give you optimal, C++ legal, zero init, as if you wrote memset(this,
    0, sizeof(*this)) in a default constructor.

    But, IMO... All this is an abomination. Language rules should change
    so that you can legally memset such things in a ctor.

    Goran.
     
    Goran, Feb 17, 2011
    #1
    1. Advertising

  2. Goran

    Fred Zwarts Guest

    Re: If there are many member variables in a class, how can I initialize them fast in the constructor?

    "Goran" <> wrote in message
    news:
    > On Feb 17, 4:02 am, KaiWen <> wrote:
    >> eg:
    >> class SomeThing {
    >> public:
    >> SomeThing();
    >> private:
    >> a
    >> b
    >> c
    >> ...
    >> ...
    >> // a lot of variables
    >>
    >> };
    >>
    >> If this is not a derived class(there is no vptr), can I use
    >> memset in constructor?

    >
    > In practice, yes, in theory, no. In theory, you can't do memset on
    > anything but POD types, and current (not C++0x) POD type rules are
    > quite strict (even a default ctor is out, which is IMO stupid).
    >
    > If you need that your stuff is zeroed out, here's a possible
    > workaround:
    >
    > template<typename POD>
    > POD ZeroedPOD()
    > {
    > POD result;
    > memset(&result, 0, sizeof result);
    > return result;
    > }
    >
    > namespace SomeThingDetails
    > {
    > struct Members
    > {
    > TYPEa a;
    > TYPEb b;
    > //...
    > TYPEx x;
    > }
    > };
    >
    > class SomeThing : SomeThingDetails::Members
    > {
    > SomeThing(params) :
    > SomeThingDetails::Members(ZeroedPOD<SomeThingDetails::Members>())
    > };
    >
    > ZeroedPOD gives you, a zeroed-out POD. Return value optimization and
    > inlining during optimization (a rather safe, but not 100% safe, bet)
    > give you optimal, C++ legal, zero init, as if you wrote memset(this,
    > 0, sizeof(*this)) in a default constructor.
    >
    > But, IMO... All this is an abomination. Language rules should change
    > so that you can legally memset such things in a ctor.


    Am I correct that the conclusion of another topic was that the use of
    memset(&result, 0, sizeof result)
    is dangerous? In practice it may work on many implementations,
    but if class SomeThing has other members following Members,
    or if another class with new members is derived from SomeThing,
    then the memset may overwrite those members.
    E.g., in the case of
    struct Members
    {
    double a;
    char b;
    }

    using a "sizeof result" in memset may clear (because of alignment)
    some memory following b, but it is possible that derived classes
    placed members there.
    So, even this work-around may work in practice,
    but is not guaranteed to work in all cases.
     
    Fred Zwarts, Feb 17, 2011
    #2
    1. Advertising

  3. Goran

    Goran Guest

    On Feb 17, 10:54 am, "Fred Zwarts" <> wrote:
    > "Goran" <> wrote in message
    >
    > news:
    >
    >
    >
    > > On Feb 17, 4:02 am, KaiWen <> wrote:
    > >> eg:
    > >> class SomeThing {
    > >> public:
    > >> SomeThing();
    > >> private:
    > >> a
    > >> b
    > >> c
    > >> ...
    > >> ...
    > >> // a lot of variables

    >
    > >> };

    >
    > >> If this is not a derived class(there is no vptr), can I use
    > >> memset in constructor?

    >
    > > In practice, yes, in theory, no. In theory, you can't do memset on
    > > anything but POD types, and current (not C++0x) POD type rules are
    > > quite strict (even a default ctor is out, which is IMO stupid).

    >
    > > If you need that your stuff is zeroed out, here's a possible
    > > workaround:

    >
    > > template<typename POD>
    > > POD ZeroedPOD()
    > > {
    > >   POD result;
    > >   memset(&result, 0, sizeof result);
    > >   return result;
    > > }

    >
    > > namespace SomeThingDetails
    > > {
    > >   struct Members
    > >   {
    > >     TYPEa a;
    > >     TYPEb b;
    > >     //...
    > >     TYPEx x;
    > >   }
    > > };

    >
    > > class SomeThing : SomeThingDetails::Members
    > > {
    > >   SomeThing(params) :
    > > SomeThingDetails::Members(ZeroedPOD<SomeThingDetails::Members>())
    > > };

    >
    > > ZeroedPOD gives you, a zeroed-out POD. Return value optimization and
    > > inlining during optimization (a rather safe, but not 100% safe, bet)
    > > give you optimal, C++ legal, zero init, as if you wrote memset(this,
    > > 0, sizeof(*this)) in a default constructor.

    >
    > > But, IMO... All this is an abomination. Language rules should change
    > > so that you can legally memset such things in a ctor.

    >
    > Am I correct that the conclusion of another topic was that the use of
    > memset(&result, 0, sizeof result)
    > is dangerous? In practice it may work on many implementations,
    > but if class SomeThing has other members following Members,
    > or if another class with new members is derived from SomeThing,
    > then the memset may overwrite those members.
    > E.g., in the case of
    >    struct Members
    >    {
    >      double a;
    >      char b;
    >    }
    >
    > using a "sizeof result" in memset may clear (because of alignment)
    > some memory following b, but it is possible that derived classes
    > placed members there.
    > So, even this work-around may work in practice,
    > but is not guaranteed to work in all cases.


    I still think what I wrote above must work. Note that ZeroedPOD works
    on a standalone object, not on Members part of SomeThing. Once zeroing
    is done, "result" is __assigned__ to a subobject Members of SomeThing.
    So, even if something after "Members" part in SomeThing was aligned
    bizarrely, said assignment would have to assign correctly (or else
    compiler is bloody broken!). But normally, that won't happen, but
    rather, RVO and inlining will kick in.

    On a related note, correct approach is to just use a default ctor for
    all members (Members() : a(), b(), ...) because however fast, memset
    won't beat (warning: imaginary assembly ahead)

    xor acc, acc;
    mov [this+offsetof(Members::a)], acc;
    mov [this+offsetof(Members::b)], acc;
    ....

    with a reasonable number of members.

    And IIRC, there's at least one compiler that watches out for exactly
    this scenario and switches from/to memset / hand-written assembly like
    above depending on cost/benefit analysis.

    Goran.
     
    Goran, Feb 17, 2011
    #3
  4. Goran

    Bo Persson Guest

    Re: If there are many member variables in a class, how can I initialize them fast in the constructor?

    Goran wrote:
    > On Feb 17, 4:02 am, KaiWen <> wrote:
    >> eg:
    >> class SomeThing {
    >> public:
    >> SomeThing();
    >> private:
    >> a
    >> b
    >> c
    >> ...
    >> ...
    >> // a lot of variables
    >>
    >> };
    >>
    >> If this is not a derived class(there is no vptr), can I use
    >> memset in constructor?

    >
    > In practice, yes, in theory, no. In theory, you can't do memset on
    > anything but POD types, and current (not C++0x) POD type rules are
    > quite strict (even a default ctor is out, which is IMO stupid).
    >
    > If you need that your stuff is zeroed out, here's a possible
    > workaround:
    >
    > template<typename POD>
    > POD ZeroedPOD()
    > {
    > POD result;
    > memset(&result, 0, sizeof result);
    > return result;
    > }
    >
    > namespace SomeThingDetails
    > {
    > struct Members
    > {
    > TYPEa a;
    > TYPEb b;
    > //...
    > TYPEx x;
    > }
    > };
    >
    > class SomeThing : SomeThingDetails::Members
    > {
    > SomeThing(params) :
    > SomeThingDetails::Members(ZeroedPOD<SomeThingDetails::Members>())
    > };
    >
    > ZeroedPOD gives you, a zeroed-out POD. Return value optimization and
    > inlining during optimization (a rather safe, but not 100% safe, bet)
    > give you optimal, C++ legal, zero init, as if you wrote memset(this,
    > 0, sizeof(*this)) in a default constructor.
    >
    > But, IMO... All this is an abomination. Language rules should change
    > so that you can legally memset such things in a ctor.
    >


    Why? To save some typing?

    If you have even a half decent optimizer in your compiler, it will do
    the equivalent of memset (or better!) if that is possible. A couple of
    decades ago, memset was important for the stupid C compilers used at
    the time. Nowadays it is not.

    Trust your compiler!



    Bo Persson
     
    Bo Persson, Feb 18, 2011
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. E11
    Replies:
    1
    Views:
    4,792
    Thomas Weidenfeller
    Oct 12, 2005
  2. Siemel Naran
    Replies:
    4
    Views:
    809
    Micah Cowan
    Jan 12, 2005
  3. Generic Usenet Account
    Replies:
    10
    Views:
    2,248
  4. Replies:
    9
    Views:
    961
  5. Ian Collins
    Replies:
    4
    Views:
    332
    itaj sherman
    Feb 17, 2011
Loading...

Share This Page