Почему работает передача по значению?
Ваш код работает из-за перегрузки конструктора smart_ptr
(9) :
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
Создает shared_ptr, который разделяет владение объектом, управляемым r.Если r не управляет объектом, это также не управляет объектом.Перегрузка шаблона не участвует в разрешении перегрузки, если Y неявно не преобразуется в (до C ++ 17), совместим с (начиная с C ++ 17) T *.
Почему он не компилируется, когда метод ожидает shared_ptr<const Widget>&
?
Если вы измените сигнатуру на
void f(shared_ptr<const Widget>& ){}
Вы не можете иметь преобразование и передачу в метод водин шаг больше, потому что временный (тот, который получается в результате преобразования) не может связываться с неконстантной ссылкой.Тем не менее, вы все равно можете сделать это в два этапа:
int main(){
std::shared_ptr<Widget> p;
std::shared_ptr<const Widget> p2{p};
// f(p); // error: cannot bind non-const reference to temporary
f(p2); // OK
return 0;
}
Есть ли какие-то накладные расходы?
Относительно накладных расходов: Да, существует smart_ptr<const Widget>
, который создается изатем передается методу (как это явно показано в приведенном выше фрагменте).
Почему он снова работает, когда метод ожидает const shared_ptr<const Widget>&
?
Относительноваше редактирование, почему оно работает снова, если вы измените подпись на это:
void f(const shared_ptr<const Widget>& ){}
В этом случае, если вы передаете shared_ptr<Widget>
, конверсия все еще происходит.Однако теперь временному результату, полученному в результате преобразования, разрешено связываться с константной ссылкой.В любом случае, метод не может изменять его, поэтому нет опасности пропустить временную переменную.
Еще один пример
Обратите внимание, что временные файлы, не привязанные к неконстантным ссылкам, являются редким случаем C ++, помогающим избежать глупых ошибок.Учтите это:
void foo(int& x) { x += 2; }
int bar() { return 3; }
int main() { foo(bar()); } // error !
Просто не имеет смысла передавать значение r в функцию, которая ожидает неконстантную ссылку на значение l.Вы не сможете наблюдать изменения, сделанные foo
в значении, возвращенном bar
.
Передача указаний по smartpointers @ cpp core
Что касается передачи указателей smartpoinc-функции в функции, обратите внимание, что в cpp coreguidelines есть некоторые пункты по этому поводу.Суть заключается в следующем: если метод не участвует в подсчете ссылок (вероятно, наиболее распространенном случае), тогда передайте не Smartpointer, а необработанный указатель.