调用 std::set<Type*>::find 时避免 const_cast

Posted

技术标签:

【中文标题】调用 std::set<Type*>::find 时避免 const_cast【英文标题】:Avoiding const_cast when calling std::set<Type*>::find 【发布时间】:2016-05-09 14:11:59 【问题描述】:

有什么好的方法可以避免下面的const_cast,同时保持 const 的正确性?

如果没有const_cast,下面的代码将无法编译。 set::find 获得对集合键类型的 const 引用,因此在我们的例子中,它保证不会更改传入的指针值;但是,它不能保证不改变指针指向的内容。

class C 
public:
   std::set<int*> m_set;

   bool isPtrInSet(const int* ptr) const
   
       return m_set.find(const_cast<int*>(ptr)) != m_set.end();
   
;

【问题讨论】:

您在一个返回 bool 的函数中返回一个迭代器,此代码当前无法编译。你的意思是使用return m_set.find(const_cast&lt;int*&gt;(ptr)) != std::cend(m_set); 糟糕,已修复。谢谢 std::find 可以提供帮助。我想知道他们是否曾经部分专门化它以在 std::set 边界上以对数时间运行。 【参考方案1】:

是的

在 C++14 中,您可以使用自己的比较器,将int const* 声明为透明。这将启用find() 的template overload,可以将键与任意类型进行比较。请参阅此相关SO question。这是Jonathan Wakely's explanation。

【讨论】:

【参考方案2】:

我想解释一下为什么这是不可能的基本逻辑。

假设set&lt;int*&gt;::find(const int*) 是合法的。然后您可以执行以下操作:

set<int*> s;
const int* p_const;
// fill s and p
auto it = s.find(p_const);
int* p = *it;

嘿,快!您将const int* 转换为int* 而不执行const_cast

【讨论】:

按照你的逻辑比较 const 和非 const 指针应该是非法的,或者有人可以通过find_if() 制造这个骗局。非常复杂的逻辑恕我直言【参考方案3】:

有没有什么好的方法可以避免下面的 const_cast,同时保持 const 的正确性?

我不确定我要提出的建议是否属于“好方法”。但是,如果您不介意自己迭代集合的内容,则可以避免使用 const_cast。请记住,这会将 O(log(N)) 操作转换为 O(N) 操作。

bool isPtrInSet(const int* ptr) const

   for ( auto p : m_set )
   
      if ( p == ptr )
      
         return true;
      
   
   return false;

【讨论】:

是否有人会为了避免 const_cast 而付出 O(N) vs O(log(N))? @Slava,我不会,但我不能代表所有人。

以上是关于调用 std::set<Type*>::find 时避免 const_cast的主要内容,如果未能解决你的问题,请参考以下文章

插入 std::set<std::tuple<std::string, ...>> 时重复

对于操作计数()。 std::set<void*> 或 std::unordered_set<void*> 哪个更快?

std::multimap<key, value> 和 std::map<key, std::set<value> 有啥区别?

std::set 唯一 ptr 范围插入

函数对象无法识别它获得的 param(std::set<int>)

linux C++获取两个std::set容器差异(容器元素差异)(容器元素差别)std::set_differencestd::inserter