Какова техническая проблема с std::shared_ptr::unique()
, что является причиной ее устаревания в С++ 17?
Согласно cppreference.com, std::shared_ptr::unique()
устарел на С++ 17 как
эта функция устарела с С++ 17, потому что
use_count
является лишь приближением в многопоточной среде.
Я понимаю, что это верно для use_count() > 1
: пока я держу ссылку на него, кто-то другой может одновременно отпустить его или создать новую копию.
Но если use_count()
возвращает 1 (это то, что меня интересует при вызове unique()
), тогда нет другого потока, который мог бы изменить это значение по-разному, поэтому я ожидал бы, что это должно быть безопасно
if (myPtr && myPtr.unique()) {
//Modify *myPtr
}
Забастовкa >
Результаты моего собственного поиска:
Я нашел этот документ: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0521r0.html, который предлагает отсрочку в ответ на С++ 17 CD-комментарий CA 14, но я не смог найти этот комментарий сам,
В качестве альтернативы, в этом документе предлагается добавить некоторые примечания, включая следующее:
Примечание. Если несколько потоков могут повлиять на возвращаемое значение
use_count()
, результат следует рассматривать как приблизительный. В частности,use_count() == 1
не означает, что доступ через ранее уничтоженныйshared_ptr
в любом смысле завершен. - конец примечания
Я понимаю, что это может быть в случае, когда в настоящее время указывается способ use_count()
(из-за отсутствия гарантированной синхронизации), но почему разрешение не просто указать такую синхронизацию и, следовательно, сделать вышеуказанный шаблон безопасным? Если бы существовало фундаментальное ограничение, которое не допускало бы такую синхронизацию (или сделало бы ее чрезвычайно дорогостоящей), то как можно правильно реализовать деструктор?
Обновление:
Я упустил из виду очевидный случай, представленный @alexeykuzmin0 и @rubenvb, потому что до сих пор я использовал unique()
только для экземпляров shared_ptr
, которые не были доступны для других потоков. Поэтому не было никакой опасности, что этот конкретный случай будет скопирован радикально.
Мне все равно было бы интересно узнать, что такое CA 14, потому что я считаю, что все мои варианты использования для unique()
будут работать, пока гарантируется синхронизация с тем, что происходит с разными экземплярами shared_ptr
на других потоки. Так что это по-прежнему кажется полезным инструментом для меня, но я могу упустить что-то фундаментальное здесь.
Чтобы проиллюстрировать то, что я имею в виду, рассмотрим следующее:
class MemoryCache {
public:
MemoryCache(size_t size)
: _cache(size)
{
for (auto& ptr : _cache) {
ptr = std::make_shared<std::array<uint8_t, 256>>();
}
}
// the returned chunk of memory might be passed to a different thread(s),
// but the function is never accessed from two threads at the same time
std::shared_ptr<std::array<uint8_t,256>> getChunk()
{
auto it = std::find_if(_cache.begin(), _cache.end(), [](auto& ptr) { return ptr.unique(); });
if (it != _cache.end()) {
//memory is no longer used by previous user, so it can be given to someone else
return *it;
} else {
return{};
}
}
private:
std::vector<std::shared_ptr<std::array<uint8_t, 256>>> _cache;
};
Что-то не так с ним (если unique()
фактически синхронизируется с деструкторами других копий)?