一组weak_ptr

Ele*_*Lee 6 c++ smart-pointers set weak-ptr c++11

这是代码:

struct lex_compare {
    bool operator() (const weak_ptr<int> &lhs, const weak_ptr<int> &rhs)const {
        return *lhs.lock() < *rhs.lock();
    }
};

int main(){
    set<weak_ptr<int>,lex_compare> intset;
    intset.insert(make_shared<int>(1));

    cout << "intset size:" << intset.size() << endl; //1
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed

}
Run Code Online (Sandbox Code Playgroud)

我想知道如何count/findweak_ptr<int>存储intset和,如果有更好的方法去完成同样的工作?

Pio*_*ycz 5

您不能将临时 shared_ptr 插入一组弱指针,因为从这个存储的弱指针指向已删除的内存的意义上说,这是内存泄漏。

intset.insert(make_shared<int>(1)); 
// after this instruction shared_ptr destructor frees the memory
Run Code Online (Sandbox Code Playgroud)

这就是为什么您无法在集合中找到它的原因 - 因为*lhs.lock()UB 在这里。

请参阅weak_ptr::lock 文档

您需要以这种方式制作 òrder 运算符:

struct lex_compare {
    bool operator() (const weak_ptr<int> &lhs, const weak_ptr<int> &rhs)const {
        auto lptr = lhs.lock(), rptr = rhs.lock();
        if (!rptr) return false; // nothing after expired pointer 
        if (!lptr) return true;  // every not expired after expired pointer
        return *lptr < *rptr;
    }
};
Run Code Online (Sandbox Code Playgroud)

所有这一切意味着 - 你需要有这个 shared_ptr sowmewhere 来计算它:

int main(){
    set<weak_ptr<int>,lex_compare> intset;
    auto shared1 = make_shared<int>(1); 
    intset.insert(shared1);

    cout << "intset size:" << intset.size() << endl; //1
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
}
Run Code Online (Sandbox Code Playgroud)

有了上述 - 您的计数将起作用。

还考虑保持 shared_ptr 设置...

[更新]

marko 在评论中指出了有效的问题。std::weak_ptr 根本不能以您使用它的方式用作键。只有当你能确保指向的值永远不会改变,指针本身也永远不会过期。看这个例子:

    set<weak_ptr<int>,lex_compare> intset;
    auto shared1 = make_shared<int>(1); 
    intset.insert(shared1);
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // works
    shared1.reset();
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
Run Code Online (Sandbox Code Playgroud)

另一个例子:

    set<weak_ptr<int>,lex_compare> intset;
    auto shared1 = make_shared<int>(1); 
    intset.insert(shared1);
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // works
    *shared1 = 2;
    cout << "Does 1 exist?"<< intset.count(make_shared<int>(1))<<endl; // failed
Run Code Online (Sandbox Code Playgroud)

您可以保留 std::shared_ptr 以防止指针的设置过期 - 并且 std::shared_ptr 具有operator <- 但该运算符比较指针本身 - 而不是指向的值 - 所以更好std::set<std::shared_ptr<int>>- 但最好的是std::set<int>

或更改std::set<...>--> std::vector<std::weak_ptr<int>>- 并使用count_if-- 请参阅:

vector<weak_ptr<int>> intset;
auto shared1 = make_shared<int>(1);
intset.push_back(shared1);
cout << "Does 1 exist?"<< count_if(begin(intset), end(intset), 
                                  [](auto&& elem) 
                                  { 
                                     auto ptr = elem.lock();
                                     return ptr && *ptr == 1; 
                                  }); 
Run Code Online (Sandbox Code Playgroud)

或与std::set<std::shared_ptr<int>>

set<shared_ptr<int>> intset;
auto shared1 = make_shared<int>(1);
intset.insert(shared1);
// if you can ensure shared1 value will not change:
cout << "Does 1 exist?"<< intset.count(shared1);
// if not  - use count_if - the slower than std::count
cout << "Does 1 exist?"<< count_if(begin(intset), end(intset), 
                                  [](auto&& ptr) 
                                  { 
                                     return ptr && *ptr == 1; 
                                  }); 
Run Code Online (Sandbox Code Playgroud)

  • 即使对上面的 `lex_compare` 进行了修改,这也违反了 `std::set` 假定的严格弱排序,此外,键值(通过 `lex_compare` 有效访问)被假定为不可变的 - 这是不可变的`std::weak_ptr` 的情况。结果将是重复的键值和键顺序的中断。期待随后对 `find()` 的调用会给出虚假的结果!由于缺乏密钥不变性,您也无法使用“multi_set”来解决您的问题。 (3认同)
  • `std::weak_ptr` 缺少 `operator&lt;()` - 这就是您需要提供自己的比较器的原因 - 一个非常好的理由,就是这样。 (2认同)