www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unexpected memory reuse

reply "Anonymous" <a a.com> writes:
module test;
import std.stdio;

class buffer(T, size_t sz) {
	auto arr = new T[sz];
	enum end = sz-1;
}

void foo(T, size_t sz)() {
	auto buf = new buffer!(T,sz);
	writeln("before ", buf.arr);
	foreach(ref ele; buf.arr) ++ele;
	writeln("after ", buf.arr);
}

unittest {
	foo!(uint,4);
	foo!(uint,4);

	auto a = new buffer!(uint,4);
	writeln(a.arr);
	auto b = new buffer!(uint,4);
	writeln(b.arr);
}

void main() {
	auto c = new buffer!(uint,4);
	writeln(c.arr);
}

rdmd -unittest test.d
before [0, 0, 0, 0]
after [1, 1, 1, 1]
before [1, 1, 1, 1]
after [2, 2, 2, 2]
a [2, 2, 2, 2]
b [2, 2, 2, 2]
c [2, 2, 2, 2]
[Finished in 1.3s]

I narrowed this down after much frustration. I'm using some fixed 
size buffers and thought it useful to define the size as part of 
the type, from which other aspects could be statically derived. 
Apparently it's not so useful. So I guess I can refactor the 
buffer's array length into the constructor or something, but I 
really didn't see this kind of memoization(?) coming.
Jul 31 2014
next sibling parent "Anonymous" <a a.com> writes:
Whoops, that is writeln("a ",a.arr); and so on.
Jul 31 2014
prev sibling next sibling parent reply "Sean Kelly" <sean invisibleduck.org> writes:
This looks like an optimizer bug.  Do you see the same result
with -release set vs. not, etc?
Jul 31 2014
parent "Anonymous" <a a.com> writes:
On Thursday, 31 July 2014 at 18:51:09 UTC, Sean Kelly wrote:
 This looks like an optimizer bug.  Do you see the same result
 with -release set vs. not, etc?
I get it regardless of -release or -O. Replacing the arr declaration with T[sz] arr; fixes the problem.
Jul 31 2014
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Thursday, 31 July 2014 at 18:30:41 UTC, Anonymous wrote:
 module test;
 import std.stdio;

 class buffer(T, size_t sz) {
 	auto arr = new T[sz];
This allocates an array with `sz` elements once _at compile time_, places it somewhere into the executable, and uses its address as the default initializer for the member `arr`. All instances of `buffer` (with the same template parameters) that you create and don't change `arr` have it point to the same memory. Use this instead: class buffer(T, size_t sz) { T[sz] arr; enum end = sz-1; } This embeds `arr` into the class, instead of making it a reference to a dynamic array. If you want the latter, use this: class buffer(T, size_t sz) { T[] arr; enum end = sz-1; this() { arr = new T[sz]; } }
Jul 31 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Marc Schütz:

 class buffer(T, size_t sz) {
 	auto arr = new T[sz];
This allocates an array with `sz` elements once _at compile time_, places it somewhere into the executable, and uses its address as the default initializer for the member `arr`.
Right. It's not a compiler bug. Dmd/ldc are working correctly. Bye, bearophile
Jul 31 2014
prev sibling parent "Sean Kelly" <sean invisibleduck.org> writes:
On Thursday, 31 July 2014 at 19:28:24 UTC, Marc Schütz wrote:
 On Thursday, 31 July 2014 at 18:30:41 UTC, Anonymous wrote:
 module test;
 import std.stdio;

 class buffer(T, size_t sz) {
 	auto arr = new T[sz];
This allocates an array with `sz` elements once _at compile time_, places it somewhere into the executable, and uses its address as the default initializer for the member `arr`. All instances of `buffer` (with the same template parameters) that you create and don't change `arr` have it point to the same memory.
Huh. For some reason I thought in-class initializations like this were effectively rewritten to occur as a part of the class ctor. But looking at the docs I guess this actually affects the format of the static initializer.
Jul 31 2014