2013-05-13 43 views
-6

我使用C++ 11标准的代码转换的这个问题:C++ 11:转换const int的*为int *使用unordered_set ::推

#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删除它。

+0

这不是C11。 – 2013-05-13 19:02:23

+2

投票重新开放。问题出在'set.insert(&a)'中,其中'a'的类型为'const int&'。 'a'的地址具有类型“指向const int的指针”,但是set对象正在寻找“指向(可修改)int”的指针。这种“常量”的混淆是相当普遍的,并且值得回答。 – 2013-05-13 19:06:47

+2

与你的问题无关,但你正在存储一个对象的地址,该对象可能是你的设置中的一个临时对象。一旦传递给'push'方法的'a'超出了范围,那么地址是无效的,并且如果它被引用(通过您的'equal_to'方法),则可能导致堆损坏或应用程序崩溃。 – pstrjds 2013-05-13 19:08:47

回答

2

set的键被声明为pointer-to-intint*。但这:

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

行经恒定int的地址,int const*,因此编译错误。

去除参数中的const就解决了编译器错误,如将使得密钥类型的int const*,但是这两种解决办法:

  • 许可程序的其他部分,与非const访问B实例传递给push(),更改设置中的关键之一的值,并打破了一套不变的:

    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. 
    
  • 介绍set的依赖上引用的对象的生命周期由b

    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
+0

在(hash-)集合(或有关此事的常规集合)中存储'int *',同时允许指向对象改变并具有散列函数根据指向对象计算哈希,不仅会显示未定义的行为,而且在我能想到的任何实现中肯定会崩溃。您的第三个解决方案是唯一有意义的解决方案。 (请注意,即使'b'作为const ref传入'push','b.x'也可能会改变。) – bitmask 2013-05-13 20:03:01

+0

Thanks,2选项是我最喜欢的解决方案,因为我不想使用复制构造函数。 – xgbuils 2013-05-13 20:15:07

+0

@jefebrondem,什么复制构造函数? – hmjd 2013-05-13 20:29:43