Будет ли компилятор c ++ оптимизировать удаление неиспользуемого возвращаемого значения? - PullRequest
4 голосов
/ 07 ноября 2008

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

Элементарный пример:

ReturnValue MyClass::FunctionThatAltersMembersAndNeverFails()
{
    //Do stuff to members of MyClass that never fails
    return successfulResultObject;
}

void MyClass::DoWork()
{
    // Do some stuff
    FunctionThatAltersMembersAndNeverFails();
    // Do more stuff
}

В этом случае, будет ли вообще скопирован объект ReturnValue? Это даже построено? (Я знаю, что это, вероятно, зависит от компилятора, но давайте сузим это обсуждение до популярных современных.)

РЕДАКТИРОВАТЬ: Давайте немного упростим это, так как в общем случае, похоже, нет консенсуса. Что если ReturnValue является целым числом, и мы возвращаем 0 вместо successfulResultObject?

Ответы [ 6 ]

3 голосов
/ 07 ноября 2008

Если класс ReturnValue имеет нетривиальный конструктор копирования, компилятор не должен исключать вызов конструктора копирования - это предписывается языком, на котором он вызывается.

Если конструктор копирования встроен, компилятор может встроить вызов, что, в свою очередь, может привести к исключению большей части его кода (также в зависимости от того, встроен ли FunctionThatAltersMembersAndNeverFails).

1 голос
/ 11 ноября 2008

Если возвращаемое значение является целым числом, и вы возвращаете 0 (как в отредактированном вопросе), то это может оптимизироваться.

Вы должны посмотреть на базовую сборку. Если функция не встроенная, то базовая сборка выполнит mov eax, 0 (или xor eax, eax), чтобы установить для eax (который обычно используется для целочисленных возвращаемых значений) значение 0. Если функция встроенная, это, безусловно, получит оптимизирован прочь.

Но этот senario не слишком полезен, если вы беспокоитесь о том, что происходит, когда вы возвращаете объекты размером более 32 бит. Вам нужно будет обратиться к ответам на неотредактированный вопрос, которые рисуют довольно хорошую картину: если все встроено, то большая часть будет оптимизирована. Если он не встроен, функции должны вызываться, даже если они ничего не делают, и это включает конструктор объекта (поскольку компилятор не знает, изменил ли конструктор глобальные переменные или сделал что-то еще странное) .

1 голос
/ 07 ноября 2008

Компоновщик может позаботиться об этом, даже если исходный вызывающий и вызываемый находятся в разных единицах компиляции.

Если у вас есть веские основания для беспокойства по поводу загрузки процессора, выделенной для вызова метода (преждевременная оптимизация - корень всего зла), вы можете рассмотреть множество доступных вариантов встраивания, включая (задыхаясь!) Макрос .

Вам действительно нужно оптимизировать на этом уровне?

1 голос
/ 07 ноября 2008

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

0 голосов
/ 07 ноября 2008

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

Поскольку у других есть примечания, это не тривиальный вопрос на уровне переписывания AST.


Оптимизаторы Peephole работают над представлением кода на уровне, эквивалентном языку ассемблера (но до генерации реального машинного кода). Существует возможность заметить загрузку возвращаемого значения в регистр, за которым следует перезапись без промежуточного чтения, и просто снять загрузку. Это делается на индивидуальной основе.

0 голосов
/ 07 ноября 2008

Я сомневаюсь, что большинство компиляторов могли бы сделать это, если бы они были в разных объектах компиляции (то есть в разных файлах). Может быть, если бы они были в одном файле, они могли бы.

...