【问题标题】:C++ 11: conversion const int* to int* using unordered_set::pushC++ 11:使用 unordered_set::push 将 const int* 转换为 int*
【发布时间】:2013-05-07 21:53:39
【问题描述】:

我有这个使用 c++11 标准的代码转换的问题:

#include<unordered_set>
struct B
{
   int x, y;
};

class A
{
   struct hash
   {
      std::size_t operator()( int* const a ) const
      {
         return std::hash<int>()( *a );
      }
   };

   struct equal_to
   {
      std::size_t operator()( int* const a, int* const b ) const
      {
         return std::equal_to<int>()( *a, *b );
      }
   };

   private:
      std::unordered_set< int*, hash, equal_to > set;

   public:
      void push( const B& b )
      {
         set.insert( &b.x );
      }
};

有人知道这是为什么吗?我可以解决删除“push”参数中的“const”修饰符的问题。但我不想要它,因为参数“b”没有被修改。

编辑:我对代码的简化产生了一个未引用的地址。我已经制作了一个结构 B 删除它。

【问题讨论】:

  • 投票重新开放。问题出在set.insert(&amp;a) 中,其中a 的类型为const int&amp;a 的地址类型为“指向 const int 的指针”,但 set 对象正在寻找“指向(可修改)int 的指针”。那种const 的困惑很常见,值得回答。
  • 与您的问题无关,但您存储的对象的地址可能是您集合中的临时对象。一旦传递给push 方法的a 超出范围,地址就无效了,如果它被引用(比如你的equal_to 方法),可能会导致堆损坏或应用程序崩溃。
  • 你到底有什么问题?有错误信息吗?如果有,是什么?
  • 不相关的问题:通过值传递 int 和通过 const ref 传递 int 有什么重要区别吗?
  • @maverik:在这种情况下没有相关差异

标签: c++ c++11 unordered-set const-cast


【解决方案1】:

set 的键被声明为一个 pointer-to-int,一个int*。但是这个:

void push( const B& b )
{
    set.insert( &b.x );
}

正在传递常量intint const* 的地址,因此编译器出错。

从参数中删除 const 将解决编译器错误,就像将密钥类型设为 int const* 一样,但这两种解决方案都会:

  • 允许程序的某些其他部分,非const 访问传递给push()B 实例,以更改集合中的一个键的值并破坏集合不变量:

    A a;
    
    B b1{17, 22};
    B b2{30, 22};
    
    a.push(b1);
    a.push(b2);
    
    b1.x = 30;  // set no longer contains unique keys.
    
  • 引入setb所引用对象生命周期的依赖:

    A a;
    a.push({14, 23}); // a now contains a dangling pointer.
    

最安全的解决方案是存储一个int 作为密钥,在线演示见http://ideone.com/KrykZw(感谢bitmask 的评论)。


可能的解决方案:

  1. 动态复制b.x。或者,
  2. 使用int const* 作为密钥。或者最好(避免显式动态分配),
  3. 使用int 作为键,而不是int*(参见http://ideone.com/KrykZw

【讨论】:

  • int* 存储在(散列)集(或常规集)中,同时允许指向的对象更改并让散列函数根据指向对象,不仅会表现出未定义的行为,而且在我能想到的任何实现中肯定会崩溃。您的第 3 个解决方案是唯一有意义的解决方案。 (请注意,即使 b 作为 const ref 传递给 pushb.x 也可能会发生变化。)
  • 谢谢,2 选项是我最喜欢的解决方案,因为我不想使用复制构造函数。
  • @jefebrondem,什么复制构造函数?
猜你喜欢
  • 2020-12-14
  • 2016-11-11
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 2015-11-23
  • 2014-09-20
  • 2016-08-03
  • 1970-01-01
相关资源
最近更新 更多