Efficiently passing structs

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue May 5 08:54:53 PDT 2015


On Tuesday, 5 May 2015 at 02:47:03 UTC, bitwise wrote:
> On Mon, 04 May 2015 00:16:03 -0400, Jonathan M Davis via 
> Digitalmars-d-learn <digitalmars-d-learn at puremagic.com> wrote:
>> D will move the argument if it can rather than copying it 
>> (e.g. if a
>> temporary is being passed in), which reduces the need for 
>> worrying about
>> copying like you tend to have to do in C++98, and I think that 
>> a lot of D
>> code just doesn't worry about the cost of copying structs.
>
> How exactly would you move a struct? Just a memcpy without the 
> postblit?

Because D has postblit constructors rather than copy 
constructors, copying is done by blitting the entire struct and 
then calling the postlblit constructor afterwards, so unless the 
postlbit constructor is @disabled, a struct is moveable simply by 
blitting it and not calling the postblit constructor afterwards. 
And the compiler can choose to do a move whenever a copy is 
unnecessary (e.g. return value optimization or when a temporary 
is passed to a

>> However, if you have a large object that you know is going to 
>> be
>> expensive to copy, you're either going to have to use const ref
>> (and thus probably duplicate the function to allow rvalues), or
>> you're going to need to make it a reference type rather than
>> having all of its data live on the stack (either by making
>> it so that the struct contains a pointer to its data or by 
>> making it a
>> class).
>> In general, if you're dealing with a type that is going to be
>> expensive to copy, I'd advise making it a reference type over 
>> relying on
>> const ref simply because it's less error-prone that way. It's 
>> trivial to
>> forget to use ref on a parameter, and generic code won't use 
>> it, so it'll
>> generally work better to just make it a reference type.
>>
>> - Jonathan M Davis
>
> Something like a Matrix4x4 lives in an awkward place between a 
> class and a struct. Because of the fact that a graphics engine 
> may have to deal with thousands of them per frame, both copying 
> them at function calls, and allocating/collecting thousands of 
> them per frame, are both unacceptable.
>
> I was reading up(DIP36, pull requests, forum) and it seems like 
> auto ref was supposed to do something like this. Is there a 
> reason you didn't mention it?

You could use auto ref, but then you'd have to templatize the 
function, since it only works with templated functions, and if 
you have multiple auto ref parameters, then you'll get a 
combinatorial explosion of template instantations as you call the 
function with different combinations of lvalues and rvalues. It's 
basically like declaring each of the combinations of the function 
with ref and non-ref parameters, but you don't have to declare 
them all, and it doesn't work with virtual functions. I didn't 
mention auto ref mostly just to be simple.

But because of that combinatorial explosion (be they declared 
implicitly via auto ref or manually) is a good reason IMHO to 
just not worry about this problem in most cases. It's just too 
tedious to duplicate all functions like that, and using templates 
isn't always acceptable.

In theory, auto ref could work for non-templated functions by 
making it so that underneath the hood as ref except that any time 
you passed it an rvalue, it implicitly defined an lvalue for you 
to pass to the function, but that doesn't match what happens with 
auto ref with non-templated functions, and changing the behavior 
for templated functions would be unacceptable, because it would 
reduce our ability to forward parameters without changing their 
type, so we'd end up with auto ref doing different things on 
templated and non-templated functions, which is potentially 
confusing. And that solution has simply never been agreed upon. I 
have no idea if it ever will be.

> Why not just add "rvref" to D?

Because we have too many attributes already. It's actually kind 
of astonishing that we're getting return ref, because Andrei was 
adamant that we not add any more parameter attributes, because we 
simply have too many already. I think that the only reasons that 
return ref is making it in is because of how it solves a real 
need and how simple it is, whereas Andrei is not at all convinced 
that having anything like C++'s const& in D is needed. And while 
it might be nice, for the most part, we _are_ able to mostly 
write code without worrying about it.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list