Using a delegate stored as a member of a destroyed struct?

Nicolas Sicard dransic at gmail.com
Mon Jan 27 00:17:51 PST 2014


On Monday, 27 January 2014 at 02:27:08 UTC, Steven Schveighoffer 
wrote:
> On Sun, 26 Jan 2014 18:41:00 -0500, Nicolas Sicard 
> <dransic at gmail.com> wrote:
>
>> Running a piece of code that can be reduced to:
>>
>> ---
>> import std.stdio;
>>
>> void main()
>> {
>> 	import std.range;
>> 	foreach(item; iota(0, 10).transform(2))
>> 		writeln(item);
>> }
>>
>> auto transform(T)(T list, real x)
>> {
>> 	auto t = /* new */ Transformer(x);   // line 12
>> 	return t.applyTo(list);
>> }
>>
>> struct Transformer
>> {
>> 	real delegate(real) fun;
>>
>> 	this(real x)
>> 	{
>> 		fun = (real r) => r * x;
>> 	}
>>
>> 	auto applyTo(T)(T list)
>> 	{
>> 		import std.algorithm;
>> 		return list.map!(x => fun(x));
>> 	}
>> }
>> ---
>>
>> the program segfaults. I guess it's because fun is destroyed 
>> when 't' goes out of scope in 'transform'. I would have 
>> thought that the MapResult struct returned by 'applyTo' still 
>> holds a valid copy of fun, but I'm wrong... Is there a way to 
>> do it?
>
> No. Just don't do that. The runtime is permitted to move 
> structs bit-for-bit, so you are not allowed to store a pointer 
> that references 'this'. Unless you prevent copying via @disable 
> this(this), your struct could be moved if someone, for 
> instance, passed it as a parameter on the stack, or returned it.
>
> A delegate using 'this' as the context pointer is the same 
> thing.
>
> The only way to solve this is to put the struct on the heap. 
> But why even use a struct? You could just use a closure (which 
> automatically goes on the heap if needed):
>
> auto Transformer(real x)
> {
>   return (real r) => r * x;
> }
>
> auto applyTo(X, T)(X fun, T list)
> {
>    import std.algorithm;
>    return list.map!(x => fun(x));
> }
>
> auto transform(T)(T list, real x)
> {
>    auto t = Transformer(x);
>    return t.applyTo(list);
> }
>
> -Steve

Actually I used a struct because the code is more complex, and it 
builds an array of delegates, which are returned from global 
functions, like:
---
struct Transformer
{
	real delegate(real)[] funs;

	addFun(real x)
	{
		fun ~= makeFun(x);
	}

	// etc.
}

real delegate(real) makeFun(real x)
{
	return (real r) => r * x;
}
---

This means my design was bad in the first place.
Thanks for the explanation.

Nicolas


More information about the Digitalmars-d-learn mailing list