【问题标题】:Why can I pass the key of std::map to a function that expects non-const?为什么我可以将 std::map 的键传递给需要非常量的函数?
【发布时间】:2018-01-02 03:08:29
【问题描述】:

根据std::mapdocumentation,它将键值对存储在std::pair<const Key, Value>中,因此map中的键是const。

现在假设我有一个std::map,其中的键是指向某些对象的指针。

struct S {};
struct Data {};
using MyMap = std::map<S*, Data>;

我们还假设有一个函数foo 接受S* 参数。

void foo(S* ptr) { /* modify the object (*ptr) */ }

现在,问题是:当我使用基于范围的 for 循环遍历 MyMap 时,我能够将 map 元素键传递给 foo

MyMap m = getMyMapSomehow();
for (auto elem : m)
{
    static_assert(std::is_const<decltype(elem.first)>::value, "Supposed to be `const S*`");
    foo(elem.first); // why does it compile?
}

所以,即使我的static_assert 成功(所以我假设elem.first 的类型是const S*),对foo 的调用编译得很好,因此看起来我可以修改指向常量的指针后面的对象。

为什么我能做到?

P.S. 这里有一个live example at Coliru 说明了我的观点。为简洁起见,我使用int 而不是SData

【问题讨论】:

  • 您正在制作元素的副本;你可以用那个个人副本做任何你想做的事......
  • 不要将指向 const 的指针与不可变指针混淆!
  • @KerrekSB 啊,确实!工作日结束时,我的大脑让我感到困惑 :) 谢谢!
  • 发生在最好的情况下:-)

标签: c++ pointers stl constants stdmap


【解决方案1】:

所以我假设elem.first 的类型是const S*

没有。存储在map 中的密钥是const,这意味着对于std::map&lt;S*, Data&gt;,密钥将是S* const(即const 指针),而不是const S*(即指向const 的指针)。所以传递给foo(S* ptr)就可以了,const指针本身会被复制到参数中。

【讨论】:

  • 你说得对,我将const T*T* const 混合在一起。这样的事情有时会在工作日结束时发生 :-) 谢谢!
  • @VasiliyGalkin: 注意:虽然const X*X const* 是一回事,但如果你认为,养成写X const* 的习惯会很有帮助,尤其是在使用模板和typedef 时视觉上 .
  • @Nawaz 不,我不同意。但我也不想再开始另一个const T* vs T const* Holywar ;)
  • @VasiliyGalkin:视觉上using pint = int*; 那么const pint 是什么意思? const int*?要么 ... ? :-/
  • @Nawaz 我坚信针对某种类型的原始指针的 typedef 通常是非常糟糕的做法。所以让我们同意我们在这个问题上不同意;)
【解决方案2】:

std::map&lt;K, V&gt;::value_typestd::pair&lt;const K, V&gt;,正如您所提到的。那么当S* 代替K 时,const K 是什么?答案可能会让您感到惊讶,它不是const S*。而是S* const

【讨论】:

    【解决方案3】:

    这是一个更简单的例子,看看你能不能解决:

    void f(int);          // takes a non-const int
    
    int main() {
        std::set<int> s;  // elements are const ints
        for (auto n : s) {
            f(n);         // OK!?
        }
    }
    

    【讨论】:

    • 啊,确实!我没有足够注意密钥类型是T* const 而不是const T*。谢谢!
    • auto n 进行复制,然后 f(int) 进行复制。所以我不明白这个答案试图通过使用副本来解释什么!
    • @Nawaz:这与 OP 面临的情况基本相同:可以使用(a 的副本)const set 元素调用采用非常量值的函数。请注意,如果您有f(int&amp;)for (auto&amp; n : s),则该代码将不起作用。我知道还有第二层混乱,但我认为如果你能理解这个简单的例子,你就有足够的差异信息来就原始情况提出正确的问题。
    • @KerrekSB: "请注意,如果您有 f(int&amp;)for (auto&amp; n : s),则代码将无法工作"。他们两个都不需要复制。拥有f(int)auto n 都可以!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 2019-12-14
    • 2022-07-06
    • 2017-07-06
    • 1970-01-01
    • 2011-03-14
    相关资源
    最近更新 更多