const 和非 const 键有啥区别?

Posted

技术标签:

【中文标题】const 和非 const 键有啥区别?【英文标题】:What is difference between const and non const key?const 和非 const 键有什么区别? 【发布时间】:2013-07-12 08:49:53 【问题描述】:

下面两行有什么区别?

map<int, float> map_data;
map<const int, float> map_data;

【问题讨论】:

问题很熟悉,***.com/questions/6307321/… 【参考方案1】:

intconst int 是两种不同的类型。

std::map&lt;int, float&gt;std::map&lt;const int, float&gt; 同样是不同的类型。

std::map&lt;const int, float&gt;std::map&lt;int, float&gt; 之间的区别在某种程度上类似于std::map&lt;int, float&gt;std::map&lt;std::string, float&gt; 之间的区别; 您会为每个地图类型获得新的地图类型。

在非const的情况下,内部密钥类型仍然非constint

std::map<const int, float>::key_type       => const int
std::map<int, float>::key_type             => int

但是,映射键在语义上是不可变的,并且所有允许直接访问键的映射操作(例如,取消引用迭代器,这会产生 value_typeconstify key_type

std::map<const int, float>::value_type => std::pair<const int, float>
std::map<int, float>::value_type       => std::pair<const int, float>

因此,如果您的实现允许,差异可能在很大程度上对您来说是不可见的。

但情况并非总是如此:标准正式要求您的密钥类型是可复制和可移动的,并且some implementations re-use map nodes;在这些实现下,尝试使用 const 键根本行不通。

【讨论】:

So the difference is largely invisible to you in every way that matters. -- 除非您使用复制/移动键的 stdlib(如 libc++),在这种情况下 const 版本会中断。有关相关讨论,请参阅 lists.cs.uiuc.edu/pipermail/cfe-dev/2011-July/015926.html @mitchnull 是的,好地方。 (btw!) @LightnessRacesinOrbit “标准正式要求您的密钥类型是可复制和可移动的”。关于可移动,我在我拥有的 C++ 标准副本上找不到,您能否提供参考或章节号? 这是一个很好的答案,最后它澄清了我在地图上遇到的整个const-ness 问题。 C++14 引入了transparent comparators,它增加了一些复杂性,只是为了让我们保持敏锐:) 啊,谢谢你确认keys不允许是const。我希望我的密钥是不可变的,这让我抓狂-_-【参考方案2】:

如果键是指针,常量键会很有帮助。使用 const 键不会让您在访问键时修改指向的对象,请考虑:

#include <map>
#include <string>

int glob = 10;

int main() 
    std::map<const int*, std::string> constKeyMap   &glob, "foo" ;
    std::map<int*, std::string> keyMap   &glob, "bar"  ;

    for(const auto& kv : keyMap)  *(kv.first) = 20; ; // glob = 20
    for(const auto& kv : constKeyMap)  *(kv.first) = 20; ; // COMPILE ERROR

    return 0;

【讨论】:

key_typeconst int*时,指针本身不是const,但指向的int是const。【参考方案3】:

key 已经是const,所以在这种情况下写const 是多余的。输入元素后,其key 无法更改。


编辑

如 cmets 中所述,两条线之间存在 差异。例如,如果您编写一个接受map&lt;const int, int&gt; 的函数,则不能将map&lt;int, int&gt; 传递给它,因为它们是不同的类型

但请注意,尽管它们是不同的类型,但它们的行为相同,因为映射中的键无论如何都是 const...

所以总而言之..唯一的区别是它们是两种不同的类型,你不应该关心其他任何事情。

【讨论】:

这不(完全)正确。 std::map 的接口将密钥类型公开为const,但这并不意味着这两个模板实例与此答案可能暗示的相同。 std::map&lt;const int, float&gt;std::map&lt;int, float&gt; 是 different types。 @jrok 是正确的,而这个答案不是。在前一种情况下,key_type 实际上仍然是 int @johnmac2332:让这成为一个快速的课程!= 完美,点赞!= 正确。 没有人是完美的,我们都会犯错,互相学习。我们在这里学习和帮助:) @LightnessRacesinOrbit 好的,是的!我同意你的看法。顺便说一句,您发布了一个不错的答案。是的,应该花时间发布并接受答案。我自己大部分时间都试图从基本面解释并发布长答案(但当然是延迟和低投票的帖子)。无论如何,我祝贺 Maroun 的 10K RP。 Maroun 发布了许多很好的答案,我发现他是一位有价值的贡献者。【参考方案4】:

虽然您的应用程序的行为通常是相同的,但它会对您可能使用的某些编译器产生影响。更具体的例子是什么让我首先来到这个页面:

使用 gnu 工具包将映射显式指定为map&lt;const key, value&gt; 成功构建;

但是它会导致 Studio12 Solaris x86 版本崩溃。


map&lt;key, value&gt; 在两者上都成功构建。应用程序的行为没有改变。

【讨论】:

“崩溃”以什么方式? @LightnessRacesinOrbit 抱怨std::map::insert 有多个声明。 是的,正如我上面所说的:它对编译器有影响。 通常,当我们说“崩溃”时,我们指的是进程的意外和不正常的运行时终止。编译器崩溃很少见,但确实会发生(尤其是新的语言功能),并且本质上非常严重(随着构建结果的变化)。 崩溃我的build,而不是application。我是否滥用了术语?【参考方案5】:

不同之处在于第二个变体将地图的键类型设置为const int。从“可修改性”的角度来看,这是多余的,因为映射已经将其键存储为 const 对象。

但是,这也可能导致这两个地图的行为出现意外且不明显的差异。在 C++ 中,为 T 类型编写的模板特化不同于为 const T 类型编写的特化。这意味着上述两个版本的地图最终可能会使用依赖于密钥类型的各种“卫星”模板的不同专业化。一个例子是关键比较谓词。第一个将使用std::less&lt;int&gt;,而第二个将使用std::less&lt;const int&gt;。通过利用这种差异,您可以轻松地使这些地图以不同的顺序对其元素进行排序。

对于新的 C++11 容器,如 std::unordered_map,此类问题更为明显。 std::unordered_map&lt;const int, int&gt; 甚至不会编译,因为它会尝试使用 std::hash&lt;const int&gt; 专门化来散列键。标准库中不存在这种专业化。

【讨论】:

【参考方案6】:

const 指的是一个常量,一旦定义,就不能改变......非 const 键会发生变化......甚至不能改变,只是在 const (一旦定义),并且“更改”可能会或可能不会发生在非常量的东西中。

【讨论】:

【参考方案7】:

const 设置后无法更改。是的,根据文档和其他答案,您应该记住key 已经是const

链接:http://www.cplusplus.com/reference/map/map/ 链接:http://en.cppreference.com/w/cpp/container/map

【讨论】:

对不起,我应该写 - 不能。模组进行了编辑 - 谢谢

以上是关于const 和非 const 键有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

引用变量和 const 指针变量有啥区别? [复制]

f(const string &) 和 f(const string) 有啥区别吗?

const funcName = (args) => ; 有啥区别?和 const funcName = (args) => ( );? [复制]

import 和 const 有啥区别,在 commonjs 中哪个是首选

在原始类型c ++中返回const或非常量有啥区别[重复]

(const_cast<char*> 和没有之间有啥区别?