我仍在学习c ++,现在我试图理解构造函数和析构函数。
每当我使用构造函数和析构函数时,我只会得到以下错误。 在我班上。
test(32992,0x100394380)malloc: *对象0x100707010的错误: 未分配指针 * 在malloc_error_break中设置一个断点以进行调试(lldb)
尽管我可以通过删除Destructor来消除错误,但是我知道这不是一个好的编程,因为我必须释放内存。
这是我的代码。
#include <iostream>
using namespace std;
class student{
private:
int *age, *mark1,*mark2,*mark3;
string *name;
public:
friend float avg(student);
student(){
age = new int;
mark1 = new int;
mark2 = new int;
mark3 = new int;
name = new string;
cout << "Enter student name: "; cin >> *name;
cout << "Enter student age: "; cin >> *age;
cout << "Enter student 3 marks: "; cin >> *mark1 >> *mark2 >> *mark3;
cout << endl; }
~student(){
delete age;
delete mark1;
delete mark2;
delete mark3;
delete name; }
string returnName(){
return *name; }
};
float avg(student s){
return (double)(*s.mark1+*s.mark2+*s.mark3)/3;}
int main() {
student s[2];
for (int i = 0; i < 2; i++) {
s[i];
cout << "Avg of student " << s[i].returnName() << " is " << avg(s[i]) << endl;
}
}
答案 0 :(得分:0)
问题是您要按值按值传递参数到avg()
。您的示例调用了两种不同的事物s
,因此,我将通过分别调用s_main
和s_avg
来区分它们。
当您通过值传递参数时,C ++将s_main
中的数据复制到s_avg
中。这是通过副本构造器完成的。您可以指定自己的副本构造函数,但如果不指定,则编译器会为您提供一个。默认的复制构造函数只是将数据复制过来。在您的情况下,student
由指针组成,因此默认的复制构造函数将复制指针。 它不会复制指针指向的数据。
由于s_avg
对于avg()
是本地的,因此avg
必须在返回时销毁s_avg
。因此,avg()
在第37行的末尾在student
上调用s_avg
的析构函数。实际上,这意味着avg()
删除s_main[0]
中的指针,并且s_main[1]
返回时。
这为main()
设置了问题。由于s_main[0]
和s_main[1]
在main()
本地,main
必须在返回时销毁s_main[0]
和s_main[1]
。因此,main()
在第47行的末尾在student
和s_main[0]
上调用s_main[1]
的析构函数。像以前一样,该析构函数试图删除两个{{1 }}和s_main[0]
-但它们已被删除!因此,您的问题。
有几种方法可以解决此问题。一种是遵守Igor的建议:您实际上并不需要指针。但是,我可以想象,也许您需要针对实际场景的指针,而不是这种玩具场景。在这种情况下,解决此问题的另一种方法是通过引用将参数传递给s_main[1]
。无论如何,这实际上是大多数时候在C ++中传递参数的正确方法:您不必担心复制构造函数或C ++专业的任何怪异事物。确切地说,您应该更改第12行,这样读取
avg()
然后更改第28行,使其显示为
friend float avg(student &);
然后它将正常工作。
严格来讲,除非您打算以某种方式修改数据(可能会发生),否则应使用恒定引用。在这种情况下,将第12行更改为
float avg(student & s){
第28行到
friend float avg(const student &);
并且,它将再次像魅力一样工作。
但实际上,伊戈尔是对的。现代C ++旨在帮助您避免使用指针,这恰恰是因为跟踪指针非常困难,并且错误后果非常危险。通过引用传递就是一个很好的例子。因此,除非绝对必须使用指针,否则请避免使用指针。