Часто утверждается, что разыменование интеллектуального указателя не оказывает заметного влияния на производительность. (Например, здесь: Производительность интеллектуального указателя C)
Теперь мне интересно, так ли это на самом деле. Я понимаю, что это может быть, если операции над объектом, на который ссылаются, являются атомарными.
Думая о коде на основе этих фрагментов:
class Worker
{
[...]
public:
void setDataProvider( shared_ptr<DataProvider> p )
{
m_provider = p;
}
void doWork()
{
[...]
for(;;) {
int d = m_provider->getSomeData();
[ do something with d ]
}
}
private:
shared_ptr<DataProvider> m_provider;
};
doWork()
будет выполняться постоянно, и время от времени setDataProvider()
вызывается из второго потока. Вполне нормальный сценарий использования умного указателя.
По общему мнению, setDataProvider()
требует дополнительных затрат, так как счетчик ссылок, защищенный блокировкой, должен быть изменен, а m_provider->getSomeData()
— нет. Говорят, что это сравнимо с обычным разыменованием указателя, по крайней мере, не требуется дорогостоящая блокировка.
Но как это может работать? Допустим, getSomeData()
не является атомарной операцией, в ней может быть некоторая логика и заметное время выполнения.
Как *m_provider
защищен от удаления во время выполнения getSomeData()
? Класс может быть единственным владельцем объекта. Перезапись m_provider
уменьшит счетчик ссылок указателя на единицу. Либо m_provider->getSomeData()
временно должен поднять счетчик ссылок, либо объект защищен от удаления в противном случае, пока выполняется getSomeData()
.
В обоих случаях необходим дорогостоящий механизм синхронизации/блокировки.
дополнение: в примере я использовал стандартное число shared_ptr
, так как в целом меня это интересует. Однако в реальном коде используется QSharedPointer
, поэтому меня это особенно интересует. Я наивно полагал, что оба будут иметь одинаковую безопасность потоков, что может быть неверным.
setDataProvider()
назначение общего указателя не является атомарным. Вам по-прежнему нужно использовать мьютекс, чтобы убедиться, что вы не читаете во время записи или не выполняете двойную запись. См. этот ответ для получения дополнительной информации: stackoverflow.com/a/31255038/4342498 - person NathanOliver   schedule 10.08.2015`
, которая должна использоваться для встроенного форматированияcode
. звездочка*
для курсива - person Jarod42   schedule 10.08.2015[...]provide no guarantee about the object being pointed to
. - person NathanOliver   schedule 10.08.2015