opAssign and const?
Jonathan M Davis
jmdavisProg at gmx.com
Fri May 4 20:31:47 PDT 2012
On Saturday, May 05, 2012 05:15:00 Era Scarecrow wrote:
> On Saturday, 5 May 2012 at 02:21:06 UTC, Jonathan M Davis wrote:
> > As I understand it, you don't need to do _anything_ special to
> > avoid having a temporary copied when passed to your function.
> > Because it's a temporary, it should be moved into the function
> > parameter, not copied. No postblit or opAssign will be
> > executed. It's only when it's _not_ a temporary that a copy
> > will be made. And even in _that_ case, it should be a move if
> > that function call is the last place that the variable is used.
>
> That's what I originally thought too... But when I'm dealing
> with the temporary there's something broken. So if I only have
> only the ref.
>
> Error: function X.opAssign (ref X rhs) is not callable using
> argument types (X)
>
> so;
> struct X {
> ref X opAssign(ref X rhs);
> }
>
> X func();
>
> struct Y {
> X x;
> this() {
> x = func();
> }
> }
>
> Unless there's a default it drops back to, it is only seeing the
> one assign function.
If you've declared an opAssign, I'd be very surprised if _any_ assignment
worked which didn't work with the opAssign that you declared. Once you've
declared an opAssign, you've taken over the assignment operator, and you need
to define it for all of the types that you want it to work with.
> > So, I believe that you're trying to avoid copies that will
> > never happen anyway. They would if you were dealing with C++ -
> > particularly C++98 - but not in D (C++11 fixes the problem via
> > move constructors).
>
> I'm not trying to avoid copying (Blocks are small so it's likely
> a tiny cost); I'm trying to keep arrays separate. Let's add to
> my example; I Hope I got it right based on the behavior I'm
> seeing.
>
> struct X {
> ubyte[] buffer;
> this(ubyte[] b) {
> buffer = b;
> }
> ref X opAssign(ref X rhs);
> }
>
> X func() {
> return X(new ubyte[5]);
> }
>
> void func2(){
> ubyte[15] buff;
> X x1 = X(buff[0 .. 5]);
> X x2 = X(buff[5 .. 10]);
> const X x3 = X(buff[10 .. $]);
>
> x1 = x2; //should use ref, opAssign required to keep addresses
> separate
> assert(x1.buff !is x2.buff); //must pass, else value semantics
> I'm using breaks
>
> x1 = func(); //default copy can work, but fails due to
> opAssign(ref X) existing. Works with opAssign(X)
>
> x1 = x3; //should fail and needs a (const X) or (ref const X).
>
> //but if you change to (ref const X),
> x1 = x2; //then opAssign(X) runs, making arrays x1 & x2 point
> to the same place; not what i want.
> }
>
> In my thinking i make (ref const X) then mutable versions should
> work too; but somehow it's deciding to use (X) instead of (ref
> const X). I'm promising I won't change the data, not requiring
> the data can't be changed.
According to http://dlang.org/function.html:
---------
Functions are overloaded based on how well the arguments to a function
can match up with the parameters. The function with the best match is se
lected. The levels of matching are:
1. no match
2. match with implicit conversions
3. match with conversion to const
4. exact match
---------
It picks opAssign(X) over opAssign(ref const X) with an argument of type X,
because opAssign(X) is an exact match (#4) whereas opAssign(ref const X)
requires a conversion to const (#3).
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list