Does (N)RVO apply to sub-objects (member or base) of identical size?

149 views Asked by At

With RVO we can return a local variable from a function without incurring the cost of a copy. Does this also work when returning a sub-object of variable?

From other answers I gather it does not when the complete object has a larger size than the object to be returned, as it would not fit in the space reserved for the return value. But what about the case where the complete object is otherwise "empty", i.e. the size is identical to the sub-object?


My rationale for asking this question:

Say I have a simple object

struct Data {
    std::string s;
    int i;
};

and a wrapper class which just acts as a more intelligent view of the data:

class WrapperRef {
    Data& d;
public:
    WrapperRef(Data& data) : d(data) {}
    // some dummy functions operating on the data
    char& foo() { return d.s[d.i]; }
};

This gets used internally by some functions returning Data to ease implementation, but the interface doesn't reflect this (i.e. the functions don't return the wrapper itself). So I may have a function:

Data makeTheData(...) {
    Data localData;
    WrapperRef wrapper{localData};

    // Manipulate the data using the wrapper
    // ...

    return localData;
}

Since this use case is common for my wrapper, I would like to replace this with a class that encapsulates it. I.e. I would replace the first two lines of makeTheData with a single local object that contains a Data sub-object and the functionality of the wrapper.

class ContainingWrapper {
    Data d;
public:
    ContainingWrapper() = default;
    // some dummy functions
    char& foo() { return d.s[d.i]; }

    // Convert to actual Data object. Maybe use other means instead such as a getter method?
    operator Data&() { return d; }
};

Data makeTheData(...) {
    ContainingWrapper wrapper;

    // Manipulate the data using the wrapper
    // ...

    return wrapper;
}

This would help implementing the common use case for the wrapper. The ContainingWrapper object has the same size as a Dataobject, so RVO should be technically possible.

Can this functionality be achieved (with a member or base sub-object, or maybe different means) without losing the performance (which is crucial) of RVO? Does the as if rule apply and allow the optimizer to turn the second implementation of makeTheData into the first, so that RVO is possible?

0

There are 0 answers