2016-03-31 2 views
2

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

template<typename RaiiObject, typename HandleType> 
const HandleType& ExtractHandle(const RaiiObject &value){ 

    const HandleType* val = value.get(); // get underlying managed object 
    return static_cast<const HandleType&>(*val); 
} 

На стороне вызывающего абонента, код выглядит следующим образом:

const auto &x = ExtractHandle(GetAHandle()); 

Это определенно проблема, потому что ссылка на основной объект, который мы будем получать от ExtractHandle будет болтая с Raii управление объектом было бы истекло.

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

auto x = ExtractHandle(GetAHandle()); 

Его утверждение, что, так как мы делаем копию, мы безопасны , так как х-значение, возвращаемое GetAHandle не умрёт, пока конструктор копирования для Handle вызывается. Правильно ли это предположение? Хорошо ли определено стандартом, что выше предлагаемое исправление не является UB?

Примечание: В то время как правильность и полезность этого дизайна, безусловно, может быть поставлена ​​под сомнение, точка больше вокруг копирование по значению, гарантирует ли хорошо определенное поведение

+0

он правильный, но код все еще мусор. make ExtractHandle вернет копию и сделайте с ней. Кроме того, зачем отбрасывать const? зло! –

+0

Несвязанный, но вы не можете сказать 'return * val;' вместо 'return static_cast (* val);'? – juanchopanza

+0

Большая проблема заключается в том, что 'RaiiObject :: get()' может возвращать копию. Поэтому 'val' будет указателем на rvalue. Я не знаю, как долго сохраняются значения, но я бы предположил, что копия даже не сохранится до заявления о возврате. В самом начале он будет уничтожен, когда функция завершится. Итак, если 'RaiiObject :: get()' возвращает копию 'ExtractHandle()' гарантированно возвращает недопустимую ссылку. – kamikaze

ответ

2

Это нормально.

Временное создание GetAHandle() будет уничтожено только в конце этого утверждения, при условии, что ваш конструктор копирования не сохранит никаких ручек внутренности этого объекта, вы в порядке.

(N3337) [class.temporary]/3: [...] Временные объекты уничтожаются на последнем этапе при оценке полного выражения (1.9), что (лексический) содержит точку, в которой они были созданы. [...]

2

Сделайте это правильно. Возвращает копию и сделать с ней:

template<typename RaiiObject, typename HandleType> 
HandleType ExtractHandle(const RaiiObject &value){ 

    return *value.get(); // get underlying managed object 
} 

В этом случае, любой из них будет действовать:

const auto &x = ExtractHandle(GetAHandle()); 
auto x = ExtractHandle(GetAHandle()); 

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

+0

И если 'RaiiObject' является подвижным, это так же эффективно. – MSalters

+0

Даже если это не так, RVO сделает это без затрат –

Смежные вопросы