为什么以下代码在Ideone&中显示运行时错误也在视觉工作室但不在代码块中?
#include <iostream>
using namespace std;
class myclass{
int *p;
public:
myclass(int i)
{p=new int;
*p=i;}
~myclass(){delete p;}
int *get(){return p;}
};
void show (myclass x){
int *i=x.get();
cout<<*i<<endl;
}
int main() {
myclass a(19);
show (a);
return 0;
}
我也不知道这个代码有什么问题(ideone和visual studio都有运行时错误,但代码块没有运行错误)
#include <iostream>
using namespace std;
int main() {
int *i=new int ;
int j=19;
i=&j;
cout<<*i<<endl;
delete i;
return 0;
}
我预感第一种情况 p 的记忆在 show()功能中删除一次,然后在 main()后再次删除因此删除相同的内存可能会导致此运行时错误(我不确定,是否是这种情况,请解释原因)并在void show中使用引用(myclass &amp; x )确实消除了错误,但我没有看到改变了什么,在第二种情况下,我认为错误是使用j的地址,如果分配了j的值,错误将消失,但在两者这些情况下代码块没有显示任何错误,所以如果任何人都可以澄清这个编译器的行为,那将是非常明显的(sry发布这么长的问题)。事先提前。
答案 0 :(得分:1)
您的班级管理动态分配的资源,但不遵循the rule of three。您对show
的调用涉及myclass
个对象的副本。这导致两个对象“管理”相同的存储器。其中一个在离开show()
时被销毁,其资源通过在析构函数中调用delete
来解除分配。这使得main()
中的对象持有指向解除分配内存的指针,然后它会尝试调用delete
。
这是未定义的行为。这意味着程序可能会出现一些明显的错误,但它也可能会以静默方式运行和退出。
底线是,如果你的班级需要管理资源(这是一个重要的 if ),那么遵循三条规则(或C +中的五条规则) 11)。
答案 1 :(得分:1)
好的,这是&#34;未定义行为的典型案例&#34;。是的,在您的myclass
示例中,p
被删除两次,这就是导致问题的原因。在第二种情况下,您只是删除未使用new
分配的指针,这意味着您没有按照规则执行操作。
未定义的行为是C和C ++(以及其他语言)通过说&#34;它未定义&#34;来解释所发生的事情的地方。规范这样做是为了避免在已经/没有特定行为的硬件中排除或制作昂贵的变通方法 - 例如,如果C ++标准说&#34; C ++运行时必须检测{{1}没有用delete
&#34;分配的记忆,写一个做正确事的new
会非常困难(你可能认为它是'#1}}并不是太难,对于给定的架构,它可能不是,但在16位微控制器中,它可能会增加很大的开销。因为C或C ++的基本原则之一就是&#34;你不会支付你没有要求的东西,这种开销是不可接受的。[别担心这样的方案无论如何都不能100%安全,因为它总是可能的指针可能是&#34;假的&#34;并且仍然匹配以某种方式做出的所有检查。
答案 2 :(得分:0)
您需要重载复制构造函数。
void show (myclass x){
int *i=x.get(); // here x.p points to same location as a.p
cout<<*i<<endl;
}
//here x.p is deleted in the destructor for x and so is a.p.
如前所述,如果涉及动态内存分配,建议遵循三条规则。