Применяется ли (N)RVO к подобъектам (элементу или базе) одинакового размера?

С помощью RVO мы можем вернуть локальную переменную из функции без затрат на копирование. Это также работает при возврате подобъекта переменной?

Из других ответов я понимаю, что это не так, когда полный объект имеет больший размер, чем возвращаемый объект, как это было бы не помещается в пространство, отведенное для возвращаемого значения. Но как насчет случая, когда полный объект в противном случае является «пустым», т.е. размер идентичен подобъекту?


Мое обоснование того, что я задаю этот вопрос:

Скажем, у меня есть простой объект

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

и класс-оболочка, который просто действует как более интеллектуальное представление данных:

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

Это используется внутри некоторыми функциями, возвращающими Data, чтобы упростить реализацию, но интерфейс не отражает этого (т. е. функции не возвращают саму оболочку). Итак, у меня может быть функция:

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

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

    return localData;
}

Поскольку этот вариант использования является обычным для моей оболочки, я хотел бы заменить его классом, который его инкапсулирует. т.е. Я бы заменил первые две строки makeTheData одним локальным объектом, который содержит подобъект Data и функциональность оболочки.

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;
}

Это поможет реализовать общий вариант использования оболочки. Объект ContainingWrapper имеет тот же размер, что и объект Data, поэтому RVO должен быть технически возможен.

Можно ли реализовать эту функциональность (с помощью члена или базового подобъекта или, возможно, другими средствами) без потери производительности (что крайне важно) RVO? Применяется ли правило как если бы и позволяет ли оптимизатору превратить вторую реализацию makeTheData в первую, чтобы стало возможным RVO?


person Andre    schedule 07.01.2017    source источник
comment
Я сомневаюсь, что вы получите то, что хотите, но вы изучали семантику движений?   -  person NathanOliver    schedule 08.01.2017
comment
Перенос обойдется дешевле, чем копирование, но все же не бесплатно. Кроме того, реализация с использованием чего-то вроде return std::move(wrapper.get()) будет немного более читабельной, чем оригинал, но не такой приятной, как вторая версия. Поэтому я думаю (поправьте меня, если я ошибаюсь), я получу половину преимуществ и половину недостатков.   -  person Andre    schedule 08.01.2017