c++ - 对 unique_ptrs 集的原始指针查找

标签 c++ c++11 unique-ptr c++14

我经常发现自己想写这样的代码:

class MyClass
{
public:
  void addObject(std::unique_ptr<Object>&& newObject);

  void removeObject(const Object* target);

private:
  std::set<std::unique_ptr<Object>> objects;
};

然而,std::set 接口(interface)的大部分内容对于 std::unique_ptrs 来说是无用的,因为查找函数需要 std::unique_ptr 参数(我显然没有,因为它们归集合本身所有) .

我可以想到两个主要的解决方案。

  1. 创建一个临时的 unique_ptr 用于查找。例如,上面的 removeObject() 可以这样实现:

    void MyClass::removeObject(const Object* target)
    {
      std::unique_ptr<Object> targetSmartPtr(target);
      objects.erase(targetSmartPtr);
      targetSmartPtr.release();
    }
    
  2. 将集合替换为指向 unique_ptrs 的原始指针映射。

      // ...
      std::map<const Object*, std::unique_ptr<Object>> objects;
    };
    

但是,在我看来,两者都有些愚蠢。在解决方案 1 中,erase() 不是 noexcept,因此临时的 unique_ptr 可能会删除它并不真正拥有的对象,并且 2 不必要地需要双倍的容器存储空间。

我知道 Boost 的指针容器,但与现代 C++11 标准库容器相比,它们当前的功能有限。

我最近在阅读有关 C++14 的内容,遇到了“向关联容器添加异构比较查找”。但根据我的理解,查找类型必须与键类型可比,但原始指针与 unique_ptrs 不可比。

有谁知道解决这个问题的更优雅的解决方案或即将添加到 C++ 的新功能?

最佳答案

C++14 , std::set<Key>::findtemplate函数如果 Compare::is_transparent存在。你传入的类型不需要是Key , 在你的比较器下是等价的。

所以写一个比较器:

template<class T>
struct pointer_comp {
  typedef std::true_type is_transparent;
  // helper does some magic in order to reduce the number of
  // pairs of types we need to know how to compare: it turns
  // everything into a pointer, and then uses `std::less<T*>`
  // to do the comparison:
  struct helper {
    T* ptr;
    helper():ptr(nullptr) {}
    helper(helper const&) = default;
    helper(T* p):ptr(p) {}
    template<class U, class...Ts>
    helper( std::shared_ptr<U,Ts...> const& sp ):ptr(sp.get()) {}
    template<class U, class...Ts>
    helper( std::unique_ptr<U, Ts...> const& up ):ptr(up.get()) {}
    // && optional: enforces rvalue use only
    bool operator<( helper o ) const {
      return std::less<T*>()( ptr, o.ptr );
    }
  };
  // without helper, we would need 2^n different overloads, where
  // n is the number of types we want to support (so, 8 with
  // raw pointers, unique pointers, and shared pointers).  That
  // seems silly:
  // && helps enforce rvalue use only
  bool operator()( helper const&& lhs, helper const&& rhs ) const {
    return lhs < rhs;
  }
};

然后使用它:

typedef std::set< std::unique_ptr<Foo>, pointer_comp<Foo> > owning_foo_set;

现在,owning_foo_set::find将接受 unique_ptr<Foo>Foo*shared_ptr<Foo> (或 Foo 的任何派生类)并找到正确的元素。

在 C++14 之外,您必须使用 mapunique_ptr接近,或等效的东西,作为find的签名过于严格。或者自己写set等价的。

关于c++ - 对 unique_ptrs 集的原始指针查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18939882/

相关文章:

c++ - 为什么这个 while 在给定一个字符串时会永远循环?

c++ - C++调用回调后删除一个对象

c++ - 警告:在std::unique_ptr的声明中忽略模板参数上的属性(-Wignored-attributes)

c++ - push_back(move(struct.unique_ptr)) 导致编译错误

c++ - gcc 选项 std=gnu++17 与 std=c++17

c++ - 使用循环在 C++ 中移动 Sprite (SFML)

c++ - 为介子设置正确的编译器

c++ - move 构造函数和多重继承

c++ - 在 C++ 中为 double 类型的数组创建 unique_ptr

c++ - 在 C++ 中为 filesystem::copy 使用多个复制选项