我知道给定this
的值不能在编译时确定。我不禁要问,一旦分配并构造了给定的对象,是this
的值被缓存,还是每次使用表达式时都会在运行时求值?这是激发我的问题的具体例子。请注意,这违反了C ++旨在维护的所有OOP原则和保护功能。
int main()
{
string s1 = string("I am super a super long string named s1, and won't be SSO");
string s2 = string("I am super a super long string named s2, and won't be SSO");
byte* s1interface = reinterpret_cast<byte*>(&s1);
byte* s2interface = reinterpret_cast<byte*>(&s2);
static_assert(sizeof s1 == sizeof s2);
for(int offset(0); offset < sizeof s1; ++offset)
{
*(s1interface + offset) ^= *(s2interface + offset);
*(s2interface + offset) ^= *(s1interface + offset);
*(s1interface + offset) ^= *(s2interface + offset);
}
cout << s1 << '\n' << s2 << "\n\n\n";
return 0;
}
//outputs:
//I am super a super long string **named s2**, and won't be SSO
//I am super a super long string **named s1**, and won't be SSO
//(The emphasis on the output strings was added by me to highlight the identity change)
首先,我想说这个程序不仅可以编译,而且可以始终如一地产生输出。我的问题不是基于为什么/如何运作。
按照我的看法,对象(重新)形成后,所有内部变量,甚至那些管理堆内存的内部变量都将被移植。但是,我设想了一个假设场景,其中this
由对象查询然后在内部存储。在对象移植操作之后,&me
将与在原始构造中被查询和存储的this
不一致,这将严重破坏使用this
的任何操作以及任何运行时地址反射。尽管绝对不要这样做,并且如果有人敢对自己的任何对象进行如此令人发指的事情,那么所有的赌注都将落空,《标准》是否规定对this
进行持续评估,或者只是为了this
进行评估在假设对象仅会占据放置对象的空间的情况下怎么说?
编辑:让我用另一种方式解释一下,如果在运行时该对象具有一个隐藏的内部this
,则该对象一旦分配即被写入,并且随后对this
的所有读取均读取存储的值,在移植之后&object
和this
将不相同。显然,这不是我的编译器如何实现的,但是我想知道这是出于一致性还是运气。
答案 0 :(得分:2)
对象永远不会“查询” this
的值。它作为隐式参数传递给(非静态)对象方法。
假设您有以下c ++代码:
#include <stdio.h>
class mystring
{
public:
char *data;
void print();
};
void mystring::print()
{
fputs(this->data, stdout);
}
void
main()
{
mystring s = {"Hello World"};
s.print();
}
现在看来方法print
没有任何参数,但实际上却有指向对象s
的指针。因此,编译器将生成与此c程序等效的代码。
#include <stdio.h>
struct mystring
{
char *data;
};
void mystring_print(struct mystring *this)
{
fputs(this->data, stdout);
}
void
main()
{
mystring s = {"Hello World"};
mystring_print(&s);
}
因此this
指针没有什么神奇之处。和其他参数一样,它只是一个无聊的参数。使用虚拟方法会使事情变得更加有趣,但是this
的处理保持不变
答案 1 :(得分:1)
因此,我与Stephan Lavavej(Stephan's website)接触,他一直在为Microsoft维护标准库实现。我将在下面发布他的答案。我确实要指出用户 HAL9000 基本上是正确的,但是由于Stephan的回答如此详尽,因此我将其发布,并最终将其指定为正式答案(获得比真正维护该标准的三大实施标准的人更多的官方话语)。如果您发现此答案有参考价值,则HAL9000的答案中有一个直观的示例可以增强您的想法。
斯蒂芬的话:
您不应认为“ this”指针存储在对象中。隐式参数心理模型是最准确的模型。 当函数x()在Meow对象m上调用成员函数Meow :: y()时,x()必须已经知道m的地址。它可能是局部变量(x()知道其所有局部变量在堆栈中的位置),它可能是解引用的指针(如果m是* ptr,ptr指向m),则可能通过引用传递(引用不是指针,但是它们实际上具有与指针相同的位置信息),它可能是数组上的元素(如果m是arr [idx],则arr + idx指向m),等等。所以Meow :: y( )将隐式传递m的地址,该地址在成员函数中变为“ this”。
至关重要的是,如果您的结构包含简单的旧数据(例如一堆int),并且交换了两个结构的内容,则对象不会更改身份-仅更改其内容。如果我将您所有的东西都拿到您家中,然后与别人家中的东西交换,则房屋的位置将保持不变。 (在C ++中,对象无法从一个内存地址迁移到另一个内存地址-您最多可以做的是创建一个单独的对象,移动所有内容,告诉关心旧位置的任何人改而指向新位置,然后销毁原始对象的空壳-基本上就是移动语义。)
因为“ this”实际上没有存储在任何地方,所以成本为零,这非常有用。 (这是外部虚拟成员函数,它确实使对象付出vptr成本,但这要先进得多。)
希望这会有所帮助, STL