C++ 如何将指针映射公开为常量指针映射?

C++ 如何将指针映射公开为常量指针映射?,c++,pointers,stl,map,constants,C++,Pointers,Stl,Map,Constants,我有一个类,它的成员是指针的std::map。现在,我想以只读方式公开该成员:地图和指向的对象都不允许修改。在内部,我需要这些指针是非常量的,我想将它们公开为常量 我确实有一个至少可以编译的解决方案,但我想知道我是否会遇到任何隐藏的问题 class A { public: const std::map<int, const float*>& GetMap() const { return *(reinterpret_cast< const std::map<i

我有一个类,它的成员是指针的std::map。现在,我想以只读方式公开该成员:地图和指向的对象都不允许修改。在内部,我需要这些指针是非常量的,我想将它们公开为常量

我确实有一个至少可以编译的解决方案,但我想知道我是否会遇到任何隐藏的问题

class A
{
public:
  const std::map<int, const float*>& GetMap() const { return *(reinterpret_cast< const std::map<int, const float*>* >( &m_Map)); }

private:
  std::map<int, float*> m_Map;
};
A类
{
公众:
const std::map&GetMap()const{return*(重新解释强制转换(&m_-map));}
私人:
std::map mu map;
};
我可以想到一个可能的问题:如果std::map的内部布局对于指针映射和常量指针映射是不同的,那么这将导致丑陋的bug。但我想不出任何合理的理由来解释这种情况。有人知道吗


澄清一下:我知道这是一种黑客行为,有更安全的解决方案(比如单独的访问函数)。我只是想知道这是否会因为我丢失的某些信息而立即中断。

这当然是未定义(编辑:看起来它实际上只是未指定)的行为,因为这两个映射(从语言的角度来看)是完全不相关的类型。它现在看起来可能有用,但有时它会坏掉,引起一大堆头痛

您认为,不是公开实现细节(您在内部使用映射),而是可以为类公共接口提供<代码> COSTATIORATER < /CAR> S和A<代码>查找< /代码>方法?

编辑: 见5.2.10/7:

可以创建指向对象的指针 显式转换为指向的指针 不同类型的对象。65)除 转换类型为的右值 “指向T1的指针”指向类型“指针” 到T2”(其中T1和T2是对象 类型和路线的位置 T2的要求并不更严格 比T1)的更高)并返回到其 原始类型产生原始类型 指针值,这种 未指定指针转换

从这段引文中,我们得出结论,从具有非常量值类型的映射到具有常量值类型的映射的强制转换具有未指定的行为。此外,实际上取消对转换指针的引用可能会违反严格的别名规则,并导致未定义的行为。

您可以在需要时将其作为映射保存并在内部强制转换。这是丑陋但合法的(只要你知道所有指向的值都不是常量)


至少它不涉及未定义的行为,我很确定你的解决方案确实如此。尽管正如您所说,它可能在大多数平台上大部分时间都能正常工作。

reinterpret\u cast会生成一个具有未指定行为的引用。不要那样做!使用常量迭代器

class A {
public:
  typedef std::map<int, float*> MapType;
  typedef MapType::const_iterator const_iterator;

  const_iterator begin () const { return m_Map.begin(); }

  const_iterator end () const { return m_Map.end(); }

private:
  std::map<int, float*> m_Map;
};


void some_function () {
  A my_map;

  // Code to build the map elided

  for (A::const_iterator iter = my_map.begin(); iter < my_map.end(); ++iter) {
    do_something_with_but_not_to (*iter);
  }
A类{
公众:
typedef std::map MapType;
typedef MapType::const_迭代器const_迭代器;
常量迭代器begin()常量{返回m_Map.begin();}
const_迭代器end()const{return m_Map.end();}
私人:
std::map mu map;
};
空一些函数(){
我的地图;
//删除用于构建地图的代码
对于(A::const_iterator iter=my_map.begin();iter

请注意,您还可以导出一些东西,例如返回常量迭代器的find。

这可能会导致问题的一个很好的原因是:即使二进制实现通常是相同的(通常是相同的,但谁知道呢),那么类型仍然是不同的。一些容器可能会使用一些静态(或现在在C++11中的TLS)字段(例如,为了优化/调试的目的),对于不同的类型,它们必须是不同的


想象一下,这样一个字段将是一个(初始化为null的)指针,它在构造函数中被赋予了一些重要的值(如果还没有赋值的话)。只要没有构造这种类型的对象,就可以安全地假设没有人会遵从它,并且在第一次构造函数调用之后,可以在不检查它是否为非空的情况下遵从它。您的代码可以生成从未构造过的容器,但它的方法遵从内部指针,导致难以跟踪segfault。

不幸的是,你可以使用一个指针类对象的映射(Ack.Actuple Posits),自动下注到 const 的方法与现代C++编程没有同步。这就是传播常量。+1,隐藏实现是最好的方法,即使它看起来需要更多的工作。一般来说,你是对的,但是…我不认为容器的常量指针和非常量指针版本有任何不同。你能告诉我一个有效的原因吗?或者一般来说,你可以看看排序关联容器接口,划掉任何要求容器为非常量的内容,并决定要实现的剩余部分的数量。然后编写一个类,该类适应非常量指针的映射,并实现您决定的所有内容。@Zed标准说它们可以不同,所以我不想猜测如果有这样的余地,编译器可能会这样做。@Mark B真的吗?我认为标准中没有提到…(如果我错了,请随时纠正我。:-)这更像是一个给定的可能性,因为它是一个模板类。我只是看不出任何原因。它没有复制,并且使用常量迭代器我仍然可以修改指向的对象。啊,是的,你没有复制。你正在使用未指定的行为进行引用。关于修改指向的对象:你不能使用ut使用C样式强制转换或常量强制转换。许多项目使常量强制转换为verboten(您需要豁免)。大多数项目使C样式强制转换和重新解释常量强制转换为verboten(当项目经理或项目死亡时授予豁免,以较晚者为准)。