#include <cstdio>
class baseclass
{
};
class derclass : public baseclass
{
public:
derclass(char* str)
{
mystr = str;
}
char* mystr;
};
baseclass* basec;
static void dostuff()
{
basec = (baseclass*)&derclass("wtf");
}
int main()
{
dostuff();
__asm // Added this after the answer found, it makes it fail
{
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
}
printf("%s", ((derclass*)basec)->mystr);
}
最佳答案
呃。这是那些“永远不要这样做”的例子之一。在 dostuff
中,您创建了一个 derclass
类型的临时对象,获取其地址,并设法将其传递到 dostuff
之外(通过将其分配给 basec
)。创建临时文件的行完成后,通过该指针访问它会产生未定义的行为。它的工作原理(即您的程序打印“wtf”)当然取决于平台。
为什么它在这个特定实例中起作用?要解释这一点,需要深入研究而不只是 C++。您创建一个 derclass
类型的临时对象。它存储在哪里?可能它作为一个非常短暂的临时变量存储在堆栈中。您获取它的地址(堆栈中的地址)并存储它。
稍后,当您访问它时,您仍然有一个指向堆栈的那部分的指针。由于此后没有人出现并重新使用堆栈的那部分,因此该对象的残余物仍然存在。由于对象的析构函数不会执行任何操作来清除内容(毕竟,它只是指向存储在静态数据中某处的“wtf”的指针),您仍然可以读取它。
尝试在 dostuff
和 printf
调用之间插入一些占用大量堆栈的内容。比如说,调用一个递归计算 factorial(10)
的函数。我敢打赌 printf
不再有效。
关于c++ - 为什么这行得通?这是一个小例子,但它甚至适用于更复杂的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1444112/