умный указатель на const в сигнатуре функции - PullRequest
0 голосов
/ 01 октября 2018

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

void f(std::shared_ptr<const Widget> ){}

int main(){
   std::shared_ptr<Widget> p; 
   f(p);
   return 0;
}

Я предполагаю, что в обоих случаях я плачу за приращение и уменьшение счета.

Кроме того, мне интересно, почему код не компилируется, если я определяю функцию f() со следующей сигнатурой:

void f(shared_ptr<const Widget>& ){}

Что меня больше всего удивляет, так это то, что это делает:

void f(const shared_ptr<const Widget>& ){}

1 Ответ

0 голосов
/ 01 октября 2018

Почему работает передача по значению?

Ваш код работает из-за перегрузки конструктора 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, а необработанный указатель.

...