www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Avoid initializing a struct field.

reply "jerro" <a a.com> writes:
Is there a way to avoid default initializing a struct field in D? 
The following doesn't seem to work:

struct Foo
{
     int[42] buffer = void;
     int bar;
}

I know I can do this:

Foo foo = void

But then all fields are uninitialized.
May 04 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
On Saturday, 4 May 2013 at 18:11:03 UTC, jerro wrote:
 Is there a way to avoid default initializing a struct field in 
 D? The following doesn't seem to work:

 struct Foo
 {
     int[42] buffer = void;
     int bar;
 }
I think it's supposed to work. If it doesn't work, then I think it's a compiler bug. What code have you used to test it, and what is the result you have seen? With this code: struct Foo { int[42] buffer; int bar; } int main() { Foo f; return f.bar; } DMD gives this code if I use void and if I don't use it: // With void: Dmain: sub ESP, 0ACh mov ECX, 02Bh push ESI mov ESI, offset FLAT:_D4temp3Foo6__initZ push EDI lea EDI, 8[ESP] rep movsd mov EAX, 0B0h[ESP] pop EDI pop ESI add ESP, 0ACh ret // Without void: Dmain: sub ESP, 0ACh mov ECX, 02Bh xor EAX, EAX push EDI lea EDI, 4[ESP] rep stosd mov EAX, 0ACh[ESP] pop EDI add ESP, 0ACh ret Bye, bearophile
May 04 2013
parent reply "jerro" <a a.com> writes:
 What code have you used to test it, and what is the result you 
 have seen?
I was using this code: extern(C) void foo(Foo* r) { Foo tmp; *r = tmp; } And here is the generated assembly (when using "= void"): push %rbp mov %rsp,%rbp sub $0xc0,%rsp mov %rdi,-0x10(%rbp) movabs $0x65a360,%rsi lea -0xc0(%rbp),%rdi mov $0x15,%ecx rep movsq %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) lea -0xc0(%rbp),%rsi mov -0x10(%rbp),%rdi mov $0x15,%cl rep movsq %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) movsb %ds:(%rsi),%es:(%rdi) leaveq retq The problem here is that the code copies the entire object from some static address instead of just the fields that need to be initialized, and that can be a performance problem. The same is true for your void version. I tried using float[42] instead of int[42] and found out that buffer actually isn't initialized to its default initializer if I use "= void" (the numbers were all 0 instead of NaN), but the performance cost is still there.
May 04 2013
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 04 May 2013 21:00:17 +0200
schrieb "jerro" <a a.com>:

 I tried using float[42] instead of int[42] and found out that 
 buffer actually isn't initialized to its default initializer if I 
 use "= void" (the numbers were all 0 instead of NaN), but the 
 performance cost is still there.
Zero is the magic number. A struct with only binary zeros goes to the BS section in the executable (on Windows*), taking up no file space. So it serves a purpose as is. The .init property is a key part of the language. It is used in equality comparisons as well as a template that you can create carbon copies of. "T.init" might be the default value for a parameter of templated function, or it could be used as the initial value for new entries in a list/table with code relying on it being a constant. Your point is valid to some extent, but while logical it adds complexity and increases the odds that someone doesn't expect .init to be a _random_ value. Because that's what it is to templated code that is instantiated with such a struct. *) http://d.puremagic.com/issues/show_bug.cgi?id=7319 -- Marco
May 05 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 04 May 2013 14:11:02 -0400, jerro <a a.com> wrote:

 Is there a way to avoid default initializing a struct field in D? The  
 following doesn't seem to work:

 struct Foo
 {
      int[42] buffer = void;
      int bar;
 }

 I know I can do this:

 Foo foo = void

 But then all fields are uninitialized.
Foo.init must exist, and be filled with *something*. Is it useful to FORCE buffer to not have 0 values? Or is it that you don't care what it has? In the latter, is it terrible that it's 0? I tend to think that without the bar there, it could potentially be uninitialized (not sure if this is the case). But as long as it's there, buffer must also be initialized. -Steve
May 06 2013
parent reply "jerro" <a a.com> writes:
On Monday, 6 May 2013 at 15:15:47 UTC, Steven Schveighoffer wrote:
 On Sat, 04 May 2013 14:11:02 -0400, jerro <a a.com> wrote:

 Is there a way to avoid default initializing a struct field in 
 D? The following doesn't seem to work:

 struct Foo
 {
     int[42] buffer = void;
     int bar;
 }

 I know I can do this:

 Foo foo = void

 But then all fields are uninitialized.
Foo.init must exist, and be filled with *something*. Is it useful to FORCE buffer to not have 0 values? Or is it that you don't care what it has? In the latter, is it terrible that it's 0?
I don't care what it contains, I just want to avoid initialization for performance reasons. I have something like this: struct Foo(size_t maxNItems) { Item[maxNItems] buffer; size_t nItems; size_t addItem(...){ ... } void processItems(...){...} } The user of Foo can add up to maxNItems items and then run some algorithm on them. Now say that Foo needs to support up to, say, a thousand items, but in most cases just a few of them will be added. In this case default initialization can take way more time than the actual algorithm.
May 06 2013
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 06 May 2013 15:01:42 -0400, jerro <a a.com> wrote:

 On Monday, 6 May 2013 at 15:15:47 UTC, Steven Schveighoffer wrote:
 Foo.init must exist, and be filled with *something*.  Is it useful to  
 FORCE buffer to not have 0 values?  Or is it that you don't care what  
 it has?  In the latter, is it terrible that it's 0?
I don't care what it contains, I just want to avoid initialization for performance reasons.
The issue is that bar int in there. The compiler does not generate initialization code that sets up specific members. It basically has an init value, and it memcpy's that thing onto any uninitialized struct. If you want performance, initialize the memory (all of it) yourself. You can't do any worse :) -Steve
May 06 2013