考虑以下c ++代码:
class test
{
public:
int val;
test():val(0){}
~test()
{
cout << "Destructor called\n";
}
};
int main()
{
test obj;
test *ptr = &obj;
delete ptr;
cout << obj.val << endl;
return 0;
}
我知道只应在动态分配的对象上调用delete,但现在obj会发生什么?
好的,我知道我们不应该做这样的事情,现在如果我正在编写智能指针的以下实现,我怎样才能确保这样的事情不会发生。
class smart_ptr
{
public:
int *ref;
int *cnt;
smart_ptr(int *ptr)
{
ref = ptr;
cnt = new int(1);
}
smart_ptr& operator=(smart_ptr &smptr)
{
if(this != &smptr)
{
// House keeping
(*cnt)--;
if(*cnt == 0)
{
delete ref;
delete cnt;
ref = 0;
cnt = 0;
}
// Now update
ref = smptr.ref;
cnt = smptr.cnt;
(*cnt)++;
}
return *this;
}
~smart_ptr()
{
(*cnt)--;
if(*cnt == 0)
{
delete ref;
delete cnt;
ref = 0;
cnt = 0;
}
}
};
答案 0 :(得分:3)
您在帖子中提出了两个不同的问题。我会另外回答。
但是现在obj会发生什么?
您的计划的行为是未定义。 C ++标准没有对obj
现在发生的事情发表评论。事实上,该标准也没有评论你的程序之前错误。它只是未定义。
也许您的编译器供应商会对发生的事情做出承诺,也许您可以检查程序集并预测会发生什么,但C ++,本身,并未定义会发生什么。
从实际上说 1 ,您可能会收到来自标准库的警告消息,或者您将获得seg错误,或两者兼而有之。
1:假设您在Windows或具有MMU的类UNIX系统中运行。其他规则适用于其他编译器和操作系统。
如何确保不会发生[
delete
堆栈变量]。
永远不要使用堆栈变量的地址初始化smart_ptr
。一种方法是将接口记录到smart_ptr
。另一种方法是重新定义接口,以便用户永远不会将指针传递给smart_ptr
;让smart_ptr
负责调用new
。
答案 1 :(得分:1)
您的代码具有未定义的行为,因为您在未使用new分配的指针上使用了delete。这意味着任何事情都可能发生,并且不可能说出obj
会发生什么。
我会猜测在大多数平台上你的代码会崩溃。
答案 2 :(得分:1)
删除尝试访问内存中的obj空间,但操作系统不允许执行此操作并抛出(核心转储)异常。
答案 3 :(得分:0)
未定义会发生什么,所以你不能说太多。您可以做的最好的是推测特定的实现/编译器。
答案 4 :(得分:0)
这不仅仅是未定义的行为,如其他答案所述。这几乎肯定会崩溃。
第一个问题是尝试释放堆栈变量。
第二个问题将发生在程序终止时,test
将为obj
调用析构函数。