Что происходит, когда класс / структура возвращаются БЕЗ RVO? - PullRequest
1 голос
/ 29 мая 2019

Я понимаю, что RVO вообще желателен, но что происходит, когда его нельзя применять?В частности, как созданный ассемблерный код возвращает локальный экземпляр класса / структуры своему вызывающему объекту?

MyClass callee() {
    MyClass a;
    /* RVO is disabled */
    return a;
}

void caller() {
    /* RVO is disabled */
    MyClass b = no_rvo();
}

Как выглядит стек в этом случае?Выделяет ли caller() и callee() отдельно место для a и b в стеке, тогда a копируется в b?Если это так, оператор RET в конце callee() полностью уменьшает указатель стека до того, что было раньше, или освобождается ли память стека для a после операции копирования?

1 Ответ

3 голосов
/ 29 мая 2019

Это зависит от соглашения о вызовах.Но все 32 и 64-битные соглашения о вызовах x86 делают один и тот же выбор и передают указатель на возвращаемое значение как «скрытый» первый аргумент.

callee все еще может оптимизировать a (еслииначе это прекращается) и просто сохраняются непосредственно в этот указатель возвращаемого значения.

нетривиально копируемым типам может потребоваться запустить конструктор копирования в какой-то момент и деструктор для a.


Но, повторяю: ваш фактический вопрос с включенной оптимизацией, вызывающая сторона передаст &b в качестве указателя возвращаемого значения.

С отключенной оптимизацией, я думаю, что я видел некоторые компиляторысоздайте пространство для отдельного временного возвращаемого значения, а затем скопируйте его оттуда, что весело для избыточно копируемых типов.

Теоретически указатель возвращаемого значения может указывать куда-то, кроме стековой памяти, например, если назначитьэлемент static MyClass arr[10].

Но он не должен указывать на то, что callee может получить доступ к любому другому способу, потому что вВ абстрактной машине C ++ возвращаемое значение - это отдельный объект, на который ничто не может указывать, прежде чем функция вернется.

...