Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Re: If there are many member variables in a class, how can Iinitialize them fast in the constructor? (http://www.velocityreviews.com/forums/t743701-re-if-there-are-many-member-variables-in-a-class-how-can-iinitialize-them-fast-in-the-constructor.html)

Goran 02-17-2011 08:28 AM

Re: If there are many member variables in a class, how can Iinitialize them fast in the constructor?
 
On Feb 17, 4:02*am, KaiWen <wenkai1...@gmail.com> 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<SomeThingDetai ls::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.

Fred Zwarts 02-17-2011 09:54 AM

Re: If there are many member variables in a class, how can I initialize them fast in the constructor?
 
"Goran" <goran.pusic@gmail.com> wrote in message
news:9ceb4507-f344-416a-843c-35d4ec4a8d6c@w19g2000yqa.googlegroups.com
> On Feb 17, 4:02 am, KaiWen <wenkai1...@gmail.com> 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<SomeThingDetai ls::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.

Goran 02-17-2011 06:52 PM

Re: If there are many member variables in a class, how can Iinitialize them fast in the constructor?
 
On Feb 17, 10:54*am, "Fred Zwarts" <F.Zwa...@KVI.nl> wrote:
> "Goran" <goran.pu...@gmail.com> wrote in message
>
> news:9ceb4507-f344-416a-843c-35d4ec4a8d6c@w19g2000yqa.googlegroups.com
>
>
>
> > On Feb 17, 4:02 am, KaiWen <wenkai1...@gmail.com> 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<SomeThingDetai ls::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.

Bo Persson 02-18-2011 06:58 PM

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 <wenkai1...@gmail.com> 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<SomeThingDetai ls::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




All times are GMT. The time now is 03:03 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.