В C ++, если указатель возвращается и немедленно разыменовывается, будут ли оптимизированы две операции? - PullRequest
1 голос
/ 24 сентября 2011

В C ++, если я получу и верну адрес переменной, а вызывающая сторона сразу же разыменует его, надежно ли компилятор оптимизирует эти две операции?

Причина, по которой я спрашиваю, состоит в том, что у меня есть структура данных, гдеЯ использую интерфейс, похожий на std :: map, где find () возвращает указатель (итератор) на значение и возвращает NULL (нет тривиального эквивалента .end ()), чтобы указать, что значение не найдено.

Я знаю, что хранимые переменные являются указателями, поэтому возврат NULL работает нормально, даже если я возвращал значение напрямую, но кажется, что возврат указателя на значение является более общим.В противном случае, если кто-то попытается сохранить там значение int, которое фактически равняется 0, структура данных будет утверждать, что его там нет.

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

Наконец, как насчет одной закрытой функции-члена, которая просто возвращает значение ивстроенная общедоступная функция-член, которая просто принимает адрес значения.Тогда, по крайней мере, операции адресации / разыменования будут выполняться вместе, и у них будет больше шансов на оптимизацию, в то время как все тело функции find () не будет встроено.

private:
V _find(key) {
   ... // a few dozen lines...
}


public:
inline V* find(key) {
    return &_find(key);
}

std::cout << *find(a_key);
</strike>

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


private:
W* _find(key) {
   ... // a few dozen lines...
}

public:
inline V* find(key) {
    return some_func(_find(key)); // last steps on W to get V*
}

std::cout << *find(a_key);

Или, как уже упоминал еще один респондент, мы могли бы вернуть ссылку на V в оригинальной версии (опять же, не уверены, почему мы все слепы на тривиальные вещи на первый взгляд ... см. Обсуждение.)


private:
V& _find(key) {
   ... // a few dozen lines...
}


public:
inline V* find(key) {
    return &_find(key);
}

std::cout << *find(a_key);

Ответы [ 3 ]

2 голосов
/ 24 сентября 2011

_find возвращает временный объект типа V. find затем пытается взять адрес временного и вернуть его. Временные объекты не длятся долго, отсюда и название. Поэтому временное возвращаемое _find будет уничтожено после получения его адреса. И поэтому find вернет указатель на ранее уничтоженный объект, что плохо.

1 голос
/ 24 сентября 2011

Ваш код (даже во втором его воплощении) не работает. _find возвращает V, который find уничтожается непосредственно перед возвратом его адреса.

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

1 голос
/ 24 сентября 2011

Я видел, как все пошло.Это действительно зависит от компилятора и уровня оптимизации.Даже когда он встроен, я видел случаи, когда компилятор не оптимизировал это.

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

Что вам, вероятно, следует сделать, - это сделать версию, в которой вы вручную вставляете их.Затем сравните его, чтобы увидеть, действительно ли вы получаете заметный прирост производительности.Если нет, то весь этот вопрос спорен.

...