2013-04-20 87 views
0

我是C++的noob。我有一个我无法解决的问题。我写了一个代码,以了解更好的类和过载运算符:对象崩溃的破坏者

#include <iostream> 
#include <stdlib.h> 
#include <stdarg.h> 
using namespace std; 

class vectmy { 
public: 
    int size; 
int *a; 
vectmy(int n,int val); 
~vectmy(){delete[] a; //IF I DELETE THIS PROGRAM WORKS 
} 
vectmy & operator = (const vectmy &); 
}; 

vectmy::vectmy(int n,int val){ 
    size=n; 
    a = new int[ n+1 ]; 
    for (int i=0;i<n;++i){ 
    *(a+i)=val; 
    } 
} 



    vectmy& vectmy::operator= (const vectmy& param) 
    { 
    for (int i=0;i<3;++i) a[i]=param.a[i]; 
    return *this; 
    } 



vectmy operator+(vectmy left, vectmy right) 
    { 
    vectmy result = left; 
    for (int i=0;i<3;++i) result.a[i]=result.a[i]+right.a[i]; 

    return result; 
    } 



int main() { 
int b1[3]={1,2,4}; 
vectmy d(3,2),b(3,4),c(3,0); 

c=(b+d); 

for (int j=0; j<3; ++j)cout<<c.a[j]<<' '<<endl; 
return 0; 
} 

当我运行它崩溃。如果我删除它的析构函数。为什么会发生?

+0

按照[三规则(http://en.wikipedia.org /维基/ Rule_of_three_%28C%2B%2B_programming%29)。你需要一个拷贝构造函数。 – juanchopanza 2013-04-20 11:30:06

+0

[三条法则是什么?]可能重复(http://stackoverflow.com/questions/4172722/what-is-the-rule-of-reeree) – juanchopanza 2013-04-20 11:33:54

回答

2

当我运行它崩溃。如果我删除它的析构函数。为什么会发生?

operator +创建复制left这里的:

vectmy result = left; 

既然你没有定义拷贝构造函数明确,编译器会生成一个隐含执行成员明智复制。

a数据部件的沉闷拷贝意味着该a指针将最终指向相同位置的vectmyresultleft)两个不同的实例,两者delete[]它在破坏。

这样的双删除给你的程序未定义的行为,在你的情况下,它表现为崩溃。

这是对Rule of Three点:每次有一个用户定义的拷贝构造函数,赋值运算符或析构函数的时候,你应该定义他们的所有

原因是你通常会定义其中的一个函数,因为你正在管理一些资源(在你的情况下是内存),并且你通常要在复制,销毁或分配管理资源的对象时执行适当的操作。

在这种特殊情况下,缺少正确的拷贝构造函数。这是你能怎么定义它:

vectmy::vectmy(vectmy const& v) 
{ 
    size=v.size; 
    a = new int[size]; 
    *this = v; 
} 

另外,我建议你通过原始指针,newdelete(或他们的阵列同行),以避免手动内存管理,只要你能,并考虑使用std::vector代替。

UPDATE:

还要注意,您operator +由值接受其参数,这意味着每一个参数将被复制(即,拷贝构造将被调用)。

由于副本是不是真的有必要在这里,您可能希望通过引用(至const)把你的参数:

vectmy operator + (vectmy const& left, vectmy const& right) 
//       ^^^^^^    ^^^^^^ 
+0

非常好的答案,非常感谢!当然我会使用std :: vector,它只是一个测试,看看如何使用指针数据成员的类表现行为。 – 2013-04-20 11:43:42

+0

但是我试着用这个运算符insted:'vectmy vectmy :: operator +(const vectmy param) { \t vectmy temp(3,0); \t for(int i = 0; i <3; ++ i)temp.a [i] = a [i] + param.a [i]; \t return temp; '我发现它可以和你的副本构造函数一起工作,但不是没有,尽管temp是创建的而不是被另一个复制的!你能否澄清这一点?谢谢! – 2013-04-20 12:03:05

+0

@TommasoFerrari:很高兴帮助:)原因是你的'operator +'通过value *接受它的参数*,当通过值传递参数时,创建一个副本 - 这意味着复制构造函数被调用。这就是为什么它只在你定义一个合适的拷贝构造函数时才起作用。但是,您不需要在这里按值接受您的参数 - 您不需要'operator +'参数的副本。我扩大了我的答案了一下。 – 2013-04-20 12:14:03

1

在你operator+你做

vectmy result = left; 

这将调用默认的构造函数拷贝构造函数,而你没有。因此将使用编译器变体,它不会为a成员分配内存。对于自动生成的拷贝构造函数,指针将被简单地复制,使得两个对象使用相同的指针。当删除它时,另一个指针变为无效。

您应该阅读约the rule of three