我不打算通过整个源代码,因为它是1000多行,但我特意为我感兴趣的事情构建了一个类似的案例。注意这个源代码:
#include <iostream>
using namespace std;
class Person
{
public:
Person();
Person(char*);
~Person();
Person& operator=(const Person&);
friend Person& example(const Person&);
void print() const;
private:
char* name;
};
Person::Person()
{
name = new char[12];
name = "Temp";
}
Person::~Person()
{
delete[] name;
}
Person::Person(char* _name)
{
name = new char[strlen(_name)+1];
strcpy_s(name,strlen(_name)+1,_name);
}
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
void Person::print() const
{
cout << name;
}
int main()
{
example();
return 0;
}
在这种情况下,example()函数将返回:
显然,在返回命令中调用析构函数并删除堆中的内存(因此我无法对指针做任何进一步操作 - 它指向已释放的内存 - 没有数据)。
我的问题是 - 如何避免这种行为?避免此类问题最优雅的方法是什么?
提前谢谢!
答案 0 :(得分:1)
string
而不是char[]
来避免使用new
。 Person
而不是Person&
,作为本地范围的类
他们离开范围后被摧毁。虽然这会导致一个
根据编译器设置进行复制。这当然取决于提供适当的拷贝构造函数。 为确保避免复制,请将example
的签名更改为:
void example(Person& person)
并填写函数内输入人员的字段。 Person
的范围将绑定到调用范围(或者您构造它的任何其他位置)。这种方法有缺点,例如你不能将结果链接在一起。
答案 1 :(得分:1)
您的代码包含许多逻辑错误:
Person::Person()
{
name = new char[12];
name = "Temp";
}
在上面的函数中,你分配一个包含12个元素的char数组,然后你就会忘记它,而是让name
指向一个字符串文字。
Person::~Person()
{
delete[] name;
}
whoopps。如果Person
是从默认构造函数构建的,那么这将delete
一个字符串文字。 C ++中的禁忌。
Person::Person(char* _name)
{
name = new char[strlen(_name)+1];
strcpy_s(name,strlen(_name)+1,_name);
}
不是100%确定strcpy_s
是什么,但本例中的代码分配了一个数组,似乎将字符串复制到数组中。这似乎没问题(但由于很多原因,strcpy(name, _name);
只会更好。)
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
此代码严重破坏。首先,它通过引用返回一个临时对象。一个非常糟糕的主意。它还分配了一个数组,并再一次忘记它并使用字符串文字。
让代码工作的最优雅方式(实际上是我认为唯一的方法)是首先了解C ++的基础知识是如何工作的。你应该先开始by reading a good C++ book from cover to cover,然后才能开始用C ++编写代码。
你的1000行源代码很可能只是垃圾。我不是说你是愚蠢的,只是因为你不了解C ++的基础知识。首先通过阅读来照顾它们,而不是试验编译器。
您无法通过实验来学习C ++有两个原因:
由于它的历史,这是一个复杂的,有时甚至是完全不合逻辑的语言。猜测几乎总是一个糟糕的举动。无论你多么聪明,你都无法正确猜出委员会的决定。
当你犯了一个错误时,天使没有运行时错误告诉你。很多时候,显然程序仍然有效......直到它由你的老师,老板或配偶经营。通过编写代码和观察发生的事情来猜测C ++规则是无稽之谈。
答案 2 :(得分:0)
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
上面在堆栈上创建了一个Person实例,作用于该函数。因此,当函数返回时,将调用Person的析构函数,并返回对已销毁对象(在堆栈上)的引用。
此外,您应该考虑返回Person的副本,或者您需要使用new运算符在堆上创建person实例并返回指向该实例的指针。