我最近一直在学习C ,而今天才引入 const 和const正确性的概念。为了更好地理解理论,我一直在编写一系列简单的程序,以确保我正确理解这个概念。我以为我理解了一切,但是当其中一个程序中使用 auto 关键字时,我似乎有点卡住了。
为了测试我了解const Pointer的工作方式,我写了一个简单的程序。我不会打扰发布整个内容,因为其中只有两个部分相关。我有一个具有INT类型的const数据成员的课程:
const int tryToChangeMe;
在此类i中,我还具有将const指针返回上述const int的成员函数:
const int* const MyClass::test()
{
return &tryToChangeMe;
}
在我的主要功能中,我使用上述功能,使用 auto 关键字。为了测试我认为我对 const 的了解是正确的,然后尝试通过指针重新分配 trytotochangeme 变量。喜欢:
auto temp = myClass.test();
*temp = 100;
正如我所期望的那样,由于我试图将值分配给 const 变量时造成的错误,该程序不会编译。但是,我不仅将指针返回到 const ,我还将a const 指针返回到a const (至少这就是我以为我以为我做过)。因此,为了进行测试,我试图将指针重新分配到新的内存地址,非常有信心我会遇到类似的汇编错误:
temp = new int;
,但令人困惑的是,该程序没有任何问题。踏上调试器逐步揭示,肯定的是,该指针失去了其原始地址,并被分配了一个全新的地址。想知道发生了什么事,我只是偶然发生了删除 auto 关键字,然后用变量的完整类型替换它:
const int* const temp = myClass.test();
再次测试所有内容后,结果是预期的,这次我无法将指针重新分配给新地址。
所以我想我的问题是,为什么?为什么 auto 关键字允许您绕过指针的 const 预选赛?我做错了吗?
顺便说一句,我不确定它是否重要,但我正在使用Visual Studio 2015 Preview
,如前所述,auto
忽略了顶部级别的CV Qualifier。阅读本文以了解auto
和decltype
如何工作的详细信息。
现在,即使auto
不忽略const
,在您的情况下,temp
仍然不是const
,因为如果返回的类型为非类型,则返回类型上的顶级CV-Qualifiers the返回类型都被忽略。p> g 甚至通过-Wextra
警告:在函数返回类型上忽略了类型预选赛[-wignored-Qualifiers]
可以使用C 14的decltype(auto)
来证明这一点。与auto
不同,decltype(auto)
不会丢弃参考文献和顶级CV-Qualifiers。如果通过添加以下行修改示例,则代码仍将编译,证明temp
不是const
指针。
decltype(auto) temp = myClass.test();
static_assert(std::is_same<const int*, decltype(temp)>{}, "");
另一方面,如果test()
返回具有顶级CV-Qualifier的类类型的对象,则auto
仍然会丢弃const
,但是decltype(auto)
不会。
live demo
原因是默认情况下auto
变量不是const
。您返回const
值的事实并不意味着必须将其分配给const
变量;毕竟,该值是复制的(事件,该值是指指针)。您也可以使用明确的类型规范轻松尝试。当更改变量temp
并且指针目标仍然为const
时,存储在myClass
中的值不会更改。
写
auto temp = rhs;
类型扣除的工作如下:
如果
rhs
是参考,则忽略了参考rhs
的顶级cv(const-volatile) - qualifiers 也被忽略(如果您执行auto& temp = rhs;
;在这种情况下,它们不忽略;在这种情况下,编译器模式匹配是类型)
在您的情况下,右侧的类型为
const int* const
^^^^^
top-level cv qualifier
即。const
指向const
-int
。指针与任何其他变量一样,因此它的const
- ness会被丢弃(从技术上讲,顶级的CV预选赛为const
,并且被丢弃),因此您最终会以temp
的类型为
const int*
即。非const
指向const
-int
的指针,因此可以重新分配。如果要执行const
-,则必须将左侧声明为
const auto temp = myClass.test();
^^^^^
need this
斯科特·迈耶斯(Scott Meyers)对该主题有一个很好的介绍(也可在他的上可用,有效的现代C 书籍,项目1和2免费在此处浏览),他在其中解释了template
类型的推论如何有效。一旦理解这一点,理解auto
就会变得轻而易举,因为真正的auto
类型扣除非常接近模板类型扣除系统(明显的std::initializer_list<>
例外)。
编辑
还有一个针对
的其他规则auto&& temp = rhs;
但是要了解它,您需要了解转发(通用)引用的工作方式以及参考折叠的工作方式。
我将提供一些正式的解释从标准参考搜索者的这一事实的标准来看:
N4296::7.1.6.4/7 [dcl.spec.auto]
如果占位符是自动类型的特定器,则推论类型为 使用模板参数扣除规则确定。
现在,模板参数defcution N4296::14.8.2/3 [temp.deduct]
:
[...] 8.3.5中描述的功能参数类型调整为 执行。
最后N4296::8.3.5/5 [dcl.fct]
确定每个参数的类型后,类型的任何参数 调整了" t"或"函数返回t"的"函数返回"为"指向" t"或"指针返回t"。生产后 参数类型的列表,任何顶级CV-Qualifiers修改 形成函数类型。
时,会删除参数类型。
简而