Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么std::shared\u ptr::unique()不推荐使用?_C++_Multithreading_Shared Ptr_C++17 - Fatal编程技术网

C++ 为什么std::shared\u ptr::unique()不推荐使用?

C++ 为什么std::shared\u ptr::unique()不推荐使用?,c++,multithreading,shared-ptr,c++17,C++,Multithreading,Shared Ptr,C++17,std::shared_ptr::unique()的技术问题是什么,这是它在C++17中被弃用的原因 根据std::shared_ptr::unique()在C++17中作为 此函数从C++17开始就不推荐使用,因为use\u count只是多线程环境中的近似值 我理解这对于use_count()>1来说是正确的:当我持有对它的引用时,其他人可能同时放弃他的或创建一个新副本 但是如果use\u count()返回1(这是我在调用unique()时感兴趣的),那么没有其他线程可以快速更改该值,因此

std::shared_ptr::unique()
的技术问题是什么,这是它在C++17中被弃用的原因

根据std::shared_ptr::unique()在C++17中作为

此函数从C++17开始就不推荐使用,因为
use\u count
只是多线程环境中的近似值

我理解这对于
use_count()>1来说是正确的:当我持有对它的引用时,其他人可能同时放弃他的或创建一个新副本

但是如果
use\u count()
返回1(这是我在调用
unique()
时感兴趣的),那么没有其他线程可以快速更改该值,因此我希望这应该是安全的:

if (myPtr && myPtr.unique()) {
    //Modify *myPtr
}

我自己搜索的结果: 我找到了这个文档:它提出了对C++17 CD注释CA14的反对意见,但我找不到该注释本身

作为替代方案,该文件建议添加一些注释,包括以下内容:

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;
};
注意:当多个线程可能影响
use_count()
的返回值时,应将结果视为近似值特别是,
use_count()==1
并不意味着通过先前销毁的
共享\u ptr
进行的访问在任何意义上都已完成。
-结束说明

我知道目前指定
use\u count()
的方式可能就是这种情况(由于缺乏保证的同步),但为什么解决方案不仅仅是指定这种同步,从而使上述模式安全?如果有一个基本的限制不允许这样的同步(或者使其成本高得惊人),那么如何才能正确地实现析构函数呢

更新: 我忽略了@alexeykuzmin0和@rubenvb的明显例子,因为到目前为止,我只在其他线程本身无法访问的
shared_ptr
实例上使用了
unique()。因此,没有危险,那个特定的实例会以一种快速的方式被复制

我仍然很想知道CA 14到底是关于什么的,因为我相信我的
unique()
的所有用例都可以工作,只要它保证与其他线程上不同
共享的\u 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;
};
类内存缓存{
公众:
内存缓存(大小)
:_缓存(大小)
{
用于(自动和ptr:\缓存){
ptr=std::使_共享();
}
}
//返回的内存块可能会传递到不同的线程,
//但是函数永远不会同时从两个线程访问
std::shared_ptr getChunk()
{
auto it=std::find_if(_cache.begin(),_cache.end(),[](auto&ptr){return ptr.unique();});
if(it!=\u cache.end()){
//以前的用户不再使用内存,因此可以将其提供给其他用户
归还它;
}否则{
返回{};
}
}
私人:
std::vector\u缓存;
};

它有什么问题吗(如果
unique()
实际上会与其他副本的析构函数同步)?

考虑以下代码:

// global variable
std::shared_ptr<int> s = std::make_shared<int>();

// thread 1
if (s && s.unique()) {
    // modify *s
}

// thread 2
auto s2 = s;
//全局变量
std::shared_ptr s=std::make_shared();
//线程1
如果(s&s.unique()){
//修改*s
}
//线程2
自动s2=s;
这里我们有一个经典的争用条件:
s2
可以(也可以不)在线程2中创建为
s
的副本,而线程1在
if


unique()==true
意味着没有人拥有指向同一内存的
shared\u ptr
,但并不意味着任何其他线程无法直接或通过指针或引用访问初始
shared\u ptr

为了您的查看乐趣:

本文件包含所有NB(国家机构)对Issaquah会议的意见。CA 14内容如下:

删除对use_count()和的“仅调试”限制 shared_ptr中的unique()引入了一个bug:为了让unique() 生成一个有用且可靠的值,它需要一个synchronize子句来 确保之前通过另一个引用进行的访问对用户可见 unique()的成功调用方。当前的许多实现都使用 松弛荷载,不提供此保证,因为未说明 在标准中。对于调试/提示用法,这是可以的。没有它 规范不明确且具有误导性

我认为,通过将
shared_ptr
误用为线程间同步,可以解决潜在的数据竞争问题。 它说,
use\u count()
返回不可靠的refcount值,因此,
unique()
成员函数在多线程处理时将无效

int main() {
  int result = 0;
  auto sp1 = std::make_shared<int>(0);  // refcount: 1

  // Start another thread
  std::thread another_thread([&result, sp2 = sp1]{  // refcount: 1 -> 2
    result = 42;  // [W] store to result
    // [D] expire sp2 scope, and refcount: 2 -> 1
  });

  // Do multithreading stuff:
  //   Other threads may concurrently increment/decrement refcounf.

  if (sp1.unique()) {      // [U] refcount == 1?
    assert(result == 42);  // [R] read from result
    // This [R] read action cause data race w.r.t [W] write action.
  }

  another_thread.join();
  // Side note: thread termination and join() member function
  // have happens-before relationship, so [W] happens-before [R]
  // and there is no data race on following read action.
  assert(result == 42);
}
intmain(){
int结果=0;
自动sp1=std::使_共享(0);//引用计数:1
//开始另一个线程
std::thread另一个线程([&result,sp2=sp1]{//refcount:1->2
结果=42;//[W]存储到结果
//[D]使sp2作用域过期,refcount:2->1
});
//执行多线程操作:
//其他线程可以同时递增/递减REF。
如果(sp1.unique()){/[U]refcount==1?
断言(result==42);//[R]从结果读取
//此[R]读取操作导致数据争用w.R.t[w]写入操作。
}
另一个线程。join();
//旁注:thread termination and join()成员函数
//have发生在关系之前,所以[W]发生在[R]之前
//并且在下面的读取操作上没有数据竞争。
断言(结果=42);
}
成员函数
unique()
没有任何同步效果,[D]
shared_ptr
的析构函数与[U]调用之间没有before关系