我很难理解为什么在调用delete
时调用空指针的解耦器。由于指针的内容为空,我甚至没有为{{{{ 1}}或malloc
它正在调用什么解构函数?
new
输出:
class Sak{
public:
Sak(){cout << "defalt constructor" << endl;}
~Sak(){
cout << "deconstructor" << endl;
}
};
int main(int argc, char *argv[])
{
Sak* s;
delete s;
system("PAUSE");
return EXIT_SUCCESS;
}
答案 0 :(得分:5)
您有Sak* s;
,它不会创建空引用或空引用,而是创建未初始化的指针。如果需要NULL指针,请使用Sak* s = NULL;
。
您的代码刚刚被破坏,使用s
的值(通过将其传递给delete
)而不初始化它(通过将其设置为某个已知值)。它的行为将是奇怪的,不可预测的。
答案 1 :(得分:4)
您的Sak* s
是一个未初始化的变量 - 它可能包含任何垃圾值。从未初始化的值中读取未定义的行为,因此一旦尝试,您的程序就会被破坏。
尽管如此,在实践中 - 并且为了解释观察到的行为 - 大多数实现都会读取s
堆栈地址处发生的任何内容并将其传递给delete
。如果该值恰好为0,那么delete
将无效 - 根据标准。否则 - 我们的情况类似于:
Sak* s = (Sak*)1;
delete s;
{0}通常对非0指针执行的操作是调用析构函数 - delete
- 然后尝试释放内存(这也是未定义的行为,可能或者可能不会使程序崩溃)。不过,你首先看到析构函数输出并不足为奇。
还值得注意的是,析构函数调用通常会传递给对象地址(例如上面代码的~Sak
)作为1
指针:析构函数不使用this
任何方式,甚至不是隐式的(例如,为具有非平凡析构函数的数据成员调用析构函数,例如this
),因此您的析构函数可能会成功返回。
答案 2 :(得分:3)
由于引用的内容为空
那里有两个错误。
没有参考。你有一个指针。 C ++指针和C ++引用都是句柄类型。 C#和Java中的引用以及C#中的指针也是如此。但是这些句柄类型之间不是100%重叠,它们是否支持地址算法(只有C ++和C#指针),以及它们是否可以重新分配(除了C ++引用之外)都有所不同。
< / LI>此指针的内容不为空。它没有初始化。
您的代码在野指针上调用delete
。这是未定义的行为。使用野生this
指针调用析构函数只是未定义行为可以导致的一个示例。
它在调用什么析构函数?
C ++根据用于调用它们的变量,引用或指针的类型查找非虚拟成员函数。在您的情况下,析构函数不是虚拟的。因此,编译器将delete s;
转换为逻辑以测试指针值是否为空,然后使用该指针值作为Sak::~Sak
指针调用this
析构函数,这并不奇怪。但是行为是未定义的,其他事情也可能发生,包括进程中其他内存的随机损坏以及更糟糕的情况(可能是打开文件的损坏,影响程序的未来运行)。