lvalue method

Steven Schveighoffer schveiguy at yahoo.com
Fri Oct 8 06:36:33 PDT 2010


On Fri, 08 Oct 2010 09:26:19 -0400, Benjamin Thaut  
<code at benjamin-thaut.de> wrote:

> Am 08.10.2010 11:13, schrieb Lars T. Kyllingstad:
>> On Fri, 08 Oct 2010 09:33:22 +0200, Benjamin Thaut wrote:
>>
>>> Hi, I'm writing a vec4 math struct and I have a method of which the
>>> return value has to be a lvalue so I wonder which is the correct way to
>>> do this:
>>>
>>> vec4 Normalize() const { ... } //won't work, not a lvalue
>>>
>>> ref vec4 Normalize() const {
>>>     vec4 temp;
>>>     ...
>>>     return temp;
>>> } //will this lead to a segfault or not?
>>
>> The compiler shouldn't even accept this.  When I try a similar thing,  
>> DMD
>> says "Error: escaping reference to local variable temp".
>>
>>
>>> ref vec4 Normalize() const {
>>>     vec4* temp = new vec4;
>>>     ...
>>>     return *temp;
>>> } //ugly, don't want to allocate anything on the heap
>>
>> This would work, since the variable is no longer on the stack and thus
>> survives the return of the function.
>>
>>
>>> auto ref vec4 Normalize() const {
>>>     vec4 temp;
>>>     ...
>>>     return temp;
>>> } //will this lead to a segfault?
>>
>> Well, that should compile, but it doesn't work the way you want.  'auto
>> ref' means that the function returns by ref if the return expression is
>> an lvalue *and it would not be a reference to a local or a parameter*.
>> So for this example, your function would return by value, not by ref.
>>
>>
>>> Or do I need to do it totaly in some other way?
>>
>> Yes, you do. :)  You are trying to create a variable on the stack, and
>> return it by reference.  The problem is that when the function returns,
>> its stack frame (the memory occupied by the function's local variables)
>> is "released".  At that point the variable doesn't exist anymore, and  
>> any
>> reference to it would be invalid.
>>
>> -Lars
>
> All this was only to get it to return a lvalue. I need a lvalue to be  
> able to do stuff like this.
>
> vec4 v1 = vec4(...);
> vec4 v2 = vec4(...);
> vec4 v3 = v1.Cross(v2.Normalize()).Normalize();
>
> Here it complained that v2.Normalize is not a lvalue, for whatever  
> reason.
>
> I'm trying to make my matrix class work even if it is const to prevent  
> it from coyping 16 floats everytime I pass it to a function.
>
> mat4 opMul(ref const(mat4) m1, ref const(mat4) m2) const {
>    ...
> }
>
> I tried many things, but it turned out that basically I have to get rid  
> of all the consts and let it copy the matrixes everytime.
>
> Because either it would tell me can not call  
> opMul((mat4)const,(mat4)const) const with (mat4)const, (mat4)const <- I  
> think this is because of the ref.
>
> Or it would tell me opMul(...) is not a lvalue if I try it to use it  
> like this
>
> vec4 v1,v2;
> mat4 m;
>
> vec4 res = (v1 - m * v2);
>
> I'm coming form C++ so is it the correct way to overload such operators  
> without const at all? Because obviously I don't want it to copy  
> unneccessarily.

The correct way is to use auto ref as the parameter:

struct vec4
{
    ...
    vec4 Normalize(auto ref const(vec4) param) {...}
}

But AFAIK, this doesn't really work.

What it *should* do is generate two versions of Normalize, one which  
passes param by reference for lvalues, and one that passes by value for  
rvalues.  Passing rvalues by value is more efficient and less problematic  
than passing by reference, since the value is already located on the  
stack, and there is no need to make a copy.

-Steve


More information about the Digitalmars-d-learn mailing list