让我们说我们创建一个类Student的对象,我们创建两个实例/对象类Student(即StudentA和StudentB)。我们使用浅层复制来初始化B的数据成员,如下所示:
学生B =学生A;
然后我们摧毁了StudentB。我们在这里面临悬空指针的情况吗?为什么以及如何?请解释一下。
答案 0 :(得分:5)
我们在这里遇到悬空指针的情况吗?为什么以及如何?请解释一下。
这取决于学生的实施。如果学生看起来像这样......
class Student
{
public:
char* m_name;
Student(const char* name)
{
m_name = new char[strlen(name)+1];
strcpy(m_name,name);
}
~Student()
{
delete[] m_name;
}
};
...然后有一个问题:当你复制一个学生时,你有两个指向相同m_name数据的指针,当两个学生实例被删除时,m_name数据被删除两次,这是非法的。为了避免这个问题,Student需要一个显式的复制构造函数,以便复制的Student有一个指向不同m_name数据的指针。
或者,如果学生看起来像这样......
class Student
{
public:
std::string m_name;
Student(const char* name)
: m_name(name)
{
}
};
...然后没有问题,因为魔法(即显式复制构造函数)是在std :: string类中实现的。
总之,如果类包含分配和删除的指针,则需要显式的复制构造函数(或者显式没有复制构造函数,但在任何一种情况下,不仅仅是默认构造函数)。
答案 1 :(得分:3)
并不劝阻浅版,确切地说 - 这是知道什么时候合适的问题。
这里的问题是“所有权”之一。 “Student”类是否“拥有”指向的数据,因此负责(在其析构函数中)删除该数据。
基本上,如果您获取拥有某些指向数据的对象的浅表副本,然后销毁原始数据或副本,则删除指向数据(由析构函数删除)。但是你仍然在对象中有一个没有被破坏的引用 - 一个悬垂的指针。
OTOH,如果对象不拥有指向的数据,析构函数不会删除指向的数据,并且没有问题。虽然你必须确保某些东西拥有指向的数据,否则你会有内存泄漏。
跟踪指向数据的所有权是非垃圾收集语言(如C ++)的关键技能,是应用Resource Allocation Is Initialisation模式的基础。
答案 2 :(得分:1)
简单来说: 如果您的类成员变量包含它也拥有的指针。
答案 3 :(得分:1)
另一点是成员的指向数据是不可变的。通过使用引用计数智能指针在实例之间共享它是不可观察的。例如,我有一些看起来像
的代码struct SizeContainer {
// ... stuff ...
private:
boost::shared_ptr<SizeExpression> p;
};
我没有声明复制构造函数和复制赋值运算符,因为无论如何都无法更改p
,因此它可以在多个实例之间共享。