Struct inheritance

H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Feb 24 10:34:17 PST 2015


On Tue, Feb 24, 2015 at 06:22:05PM +0000, ketmar via Digitalmars-d-learn wrote:
> On Tue, 24 Feb 2015 12:05:50 +0000, amber wrote:
> 
> > Hi,
> > 
> > Is it possible in D to have inheritance using value types, i.e.
> > structs?
> > 
> > Also I don't quite understand how copy ctors work in D. Do I need to
> > implement opAssign(S other) {}, or this(this) {} and what's the
> > difference between these two?
> > 
> > Thanks,
> > Amber
> 
> p.s. sometimes compiler can use "move" instead of "copy" for
> structures.  in this case it will not call postblit. so if you have
> some fields in your struct that depends of the structure address...
> you're in trouble.

Yes, basically, D structs are value types, and quite unlike C++ structs.
It's a trap to assume C++-like semantics for D structs, because they are
actually very different beasts. D structs should not rely on their own
address remaining static, because move semantics will cause problems,
for example:

	struct S {
		int x;
		int* p;
		this(int _x) {
			x = _x;
			p = &x;	// uh-oh
		}
		void method() {
			*p++;	// by the time this runs, the struct may
				// have moved
		}
	}

	S makeStruct() {
		return S(1);
	}

	void main() {
		auto s = makeStruct();
		s.method();
		assert(s.x == 2); // KABOOM
	}

The problem is that returning S from makeStruct() makes a bitwise copy
of the struct into main's local variable s, which has a different
address than the one created in makeStruct(). But s.p still points to
the old address of s.x, which is now pointing to invalid memory.

For even more fun, do this:

	void checkItOut(int x, S* s) {
		assert(x == 10);
		s.method();
		assert(x == 10); // KABOOM
	}

	void main() {
		auto s = makeStruct();
		s.method();
		checkItOut(10, &s);
	}

Depending on the specifics of your platform, the second assert in
checkItOut() may fail, because s.method(), via the stale pointer s.p,
will overwrite the stack location where the original s.x was (but which
has gone out of scope and is now invalid), and that old location is now
being used for one of the parameters of checkItOut(). So calling
s.method() will silently corrupt the stack where the parameter is
passed.

tl;dr, the moral of the story is, don't rely on the address of structs
in D staying the same, unless you REALLY know what you're doing. And
even then, you're just 1/8 of an inch away from shooting yourself in the
foot.


T

-- 
All problems are easy in retrospect.


More information about the Digitalmars-d-learn mailing list