'this'指针的类型

38

正如标题所述,我想了解'this'指针的类型。

我正在开发一个项目,观察到在Windows使用VC++ 2008时'this'指针的类型为"ClassName * const this"。我想知道把this指针变成常量指针的必要性和原因。谢谢。

4个回答

56

这个指针的类型要么是ClassName *,要么是const ClassName *,具体取决于它是否在类ClassName的非const或const方法内被检查。指针this不是lvalue。

class ClassName {
  void foo() {
    // here `this` has `ClassName *` type
  }

  void bar() const {
    // here `this` has `const ClassName *` type
  }
};
你上面提到的观察结果是具有误导性的。指针this不是一个L值,这意味着它不可能有ClassName * const 类型,也就是说,它不能在*右边有一个const。指针类型的非L值不能是常量或非常量。在C ++语言中根本没有这样的概念。你观察到的必须是特定编译器的内部问题。从形式上讲,这是不正确的。
以下是语言规范中相关的引用(重点在此): 9.3.2 this指针 在非静态(9.3)成员函数体中,关键字this是一个prvalue表达式,其值是调用该函数的对象的地址。类X的成员函数中this的类型是X *。如果成员函数声明为const,则this的类型是const X *;如果成员函数声明为volatile,则this的类型是volatile X *;如果成员函数声明为const volatile,则this的类型为const volatile X *。[注意:因此,在const成员函数中,通过const访问路径访问调用函数的对象。-end note]
值得注意的是,在C ++98 / C ++03时代,一些编译器使用了一种内部实现技巧:将它们的 this 指针解释为常量指针,例如类 ClassName 的非常量方法中的 ClassName * const 。这显然有助于确保this的不可修改性。已知GCC和MSVC使用了该技术。这是一种无害的技巧,因为在语言层面上,this不是L值,其常量性是不可检测的。那个额外的const通常只会在编译器发出的诊断消息中显示出来。
但是,随着C ++ 11中右值引用的出现,可以检测到此类型的this上的额外const。例如,以下代码在C ++ 11中是有效的:
struct S
{
  void foo() { S *&&r = this; }
};

然而,在仍然使用上述技巧的实现中,它通常无法编译。 GCC已经放弃了这种技术。 MSVC ++仍在使用它(截至VS2017),这会阻止上面的完全有效的代码在MSVC ++中编译。


正是我所期望的。但我并不这么认为。我观察到的行为发生在所谓的“ClassName”类的非const方法内部。好吧,我通过VC++智能感知来了解类型,当你滚动变量时它会显示类型。这可能是我得到错误类型信息的可能原因吗? - Purnima
@neuront:这没有意义。在给定的作用域中,this(或任何其他表达式)的类型不是由调用堆栈确定的。 - MSalters
@neuront:如果你有一个指向某个东西的指针,那么这个东西保证是一个左值。我上面所说的适用于this本身,而不是它所指向的内容。 - AnT stands with Russia
4
@Purnima:不行。这意味着你的《C++ Primer第4版》是错误的。我不知道这是否是有意为之的错误(为了简化)还是书中真正的错误,但说 this 是一个"const指针"总是不正确的。再次强调,this 是标量类型的右值。标量类型的右值无法是const或non-const。第四版于2001年出版,这意味着它相当古老。检查更晚的版本可能是有意义的。错误可能已经被修复了。 - AnT stands with Russia
@Purnima:我刚在TC++PL书的第10章找到了它。是的,它确实如此说明。而且,这只是Stroustrup书中的另一个错误。 - AnT stands with Russia
显示剩余7条评论

4

const表示你不能更改指针所指向的内容。

ClassName *const

与之大不相同

const ClassName *

后一种是指向对象的指针,而且对象不可修改(至少使用该指针无法修改)。前一种是指针,无法重新指向另一个对象(也不能为NULL),除非采用丑陋的转换。

当然也有两者的结合:

const ClassName *const

这是一个指针,不能被改变以指向其他内容,也不能用来更改它所指向的对象。
至于为什么您的编译器将 this 指针显示为 const,这样做确实有道理,因为您不应该让 this 指向除了初始对象之外的其他对象。

+1 好的分析。简而言之,编译器跟踪你不能使用 this = ...This& p = *this(假设 p 不是 const)。 - Tony Delroy
14
5 也不能被改变或分配。你不能执行 5 = 3。然而,5 的类型是 int。它是 int 而不是 const int。说 5 的类型是 const int 是不正确的。同样适用于 this 指针。它不是一个左值(就像 5 不是一个左值一样)。不是左值的东西不能是 const 或非 const。因此,this 指针不能是 const,上面的分析从正式的角度来看是完全错误的。 - AnT stands with Russia
我更喜欢使用 ClassName const * 而不是 const ClassName *。同样,对于 ClassName const * const,我也更倾向于使用 const ClassName * const。从右到左阅读,很容易看出 const 应用的位置。 - Thomas Eding

2

上面有很多讨论,但主贴没有给出正确的答案。人们可能不会深入评论区,因此最好将其分享为主要文章(PS)。

我对Ubuntu和VC++进行了一些调查,但都没有正确输出(使用typeid(X).name)。


类类型X的成员函数的this指针类型是X* const。如果成员函数被声明为const限定符,则该成员函数所属的类X的this指针类型是const X* const。MSDN链接


从概念上讲也是正确的,对于常规成员函数来说,“X* const”就是它不是左值的原因(因为你不能更改它的内容)。


-4
来自C++ Primer第四版的摘录:“在普通的非常量成员函数中,this的类型是指向类类型的const指针。我们可以改变this所指向的值,但不能改变this所持有的地址。在一个const成员函数中,this的类型是指向const类类型对象的const指针。我们既不能改变this所指向的对象,也不能改变this所持有的地址。”这意味着VC++ IntelliSense显示的内容是正确的。

4
不正确。这本书以及VC++智能感知都是错误的。再次强调,this指针是一个rvalue(请参见语言标准中的9.3.2 / 1)。非类rvalue不能具有const限定类型(请参见语言标准中的3.10 / 9)。无论哪本书声称什么都不相关,无论是由谁编写的。如果一些书与语言规范相矛盾,则该书是错误的。 - AnT stands with Russia
3
在语言规范的早期版本中,“this”很可能具有常量指针类型。然而,当C++98标准最终确定时,这种情况不再存在。您的书可能已经过时或者存在错误。 - AnT stands with Russia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接