指针类成员和删除职责
Pointer class member and deleting responsibilities
如果我的类有一个可以由类客户端设置的指针,我应该如何处理删除?
示例:
class A {
};
class B {
public:
void setA(A* a) {
this->a = a;
}
private:
A* a;
};
类B
的析构函数应该是什么?是否应该删除a
?正如我所看到的,用户可以通过两种方式设置这个指针:
... // Assume B object b being created elsewhere
A aObj;
A* aPtr = new A();
b.setA(&aObj); // It is not OK to use delete, and class member will
// point to invalid memory location once aObj goes out
// of scope
b.setA(aPtr); // Using new will make the pointer available even after
// this block of code
...
那么删除b的正确方法是什么呢?我是否应该在set
方法中始终执行new
?
类B的析构函数应该是什么?它应该删除吗?
类的作者您决定其语义。不要从指针、引用和delete
的角度思考。从设计的角度思考:A
和B
之间有什么关系?B
需要A
做什么?
两种常见的关系类型是委托和组合。委派意味着客户端代码使用setA
成员让实例知道它可以用于进一步使用的其他B
实例。组合意味着setA
成员用于初始化实例的内部部分。
委派的一种可能实现是使用成员指针。我建议传递一个对setA
的引用来分配给那个指针;它避开了检查CCD_ 14的问题,并使客户端代码清楚地知道不存在需要处理的所有权问题。这与多态类型兼容。
一种可能的组合实现是使用A
成员,并通过引用传递给const或通过值分配给它。另一种是使用智能指针,特别是如果A
是多晶型使用的。传递智能指针是最简单的方法,但您必须检查0
和/或记录转换。
无论你决定使用什么(无论如何都不必在这个列表中),都要将代码作为实现你的目的或设计的工具。不要让代码支配你的想法。
在我的所有示例实现中,您不必在析构函数中做任何特殊的操作。
您真的不应该有这样的类。相反,使用像shared_ptr
或unique_ptr
这样的资源管理容器来保存指向动态分配对象的指针。
正如你很容易看到的,如果你在各处随机分配动态对象,你就无法追踪谁应该对此负责。你们班的临摹和作业怎么样?构造函数中的异常怎么办?不要这么做。
我认为通常会有3种场景,请参阅下面的代码:
//class B doesn't own a
class B {
public:
void setA(A& a) {
m_a = a;
}
private:
A& m_a; //Only a reference , so need to worry about delete
};
//class B owns A
class B {
public:
void setA(std::auto_ptr<A>& a) {
m_a.reset(a.release());
}
private:
boost::scoped_ptr<A> m_a; //m_a got deleted when instance of B lifetime end
};
//class B shared A with someone else
class B {
public:
void setA(boost::shared_ptr<A>& a) {
m_a = a;
}
private:
boost::shared_ptr<A> m_a; //m_a got deleted when no one need this pointer anymore(reference counting reduced to 0)
};
您需要做出设计决策。谁应该拥有这个物体?
- B对象拥有A对象,
setA
将所有权传递给B。B的析构函数应该删除A - 某些外部代码拥有A对象。B不会删除它,但将依靠外部代码在适当的时候销毁它
- 智能指针跟踪对A对象的引用,并在所有引用被销毁时自动将其删除
带有智能指针的第三个选项是最简单、最可靠的,但这三个选项都可以使用。诀窍是选择一个并慎重考虑
在设计分析过程中,您必须回答以下问题:
- 对象A是否取决于对象B的生存期,如果是,则使用"composition",在这种情况下,对象B将创建A,并负责在对象B自身被销毁之前删除它
- 如果对象A与对象B的生存期无关,则使用"聚合"。通过B的构造函数或set方法将对象A提供给B。对象B不必担心破坏对象A,但您必须确保在B的生命周期内,A处于有效状态
- 如果A依赖于对象B的生存期,但您需要在B之前创建A,则执行"依赖注入"。这就像聚合,因为你可以在构造函数或set方法中将A传递给B,但在这种情况下,A只由B使用,没有其他对象使用A。B在销毁A之前删除了A
从外观上看,您正试图在B类中创建对a对象的引用。
要正确清理B,您必须首先检查A是否为空。类似。。。
~B()
{
if (A)
{
delete A;
A = 0;
}
}
请记住,这也会删除类之外的A对象,因为它们引用的是相同的内存。因此,在这样的情况下,如果删除a对象,您可以很容易地引用指向无效内存的指针。
顺便说一句,我也不会把它和局部变量一起使用,因为当它超出范围时,你会丢失它的地址。然而,另一方面,本地指针。。那么,一旦离开了创建A的范围,就不必担心引用无效内存了。
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- std::ofstream 作为类成员删除复制构造函数?
- 删除C++继承中虚拟类成员的代码重复
- 在对象指针上调用 Delete 是否会递归删除其动态分配的成员
- 我可以在此模板中删除此类成员吗?
- 在运行时有条件地删除类成员或跳过调用该成员对象的构造函数
- 指向重载静态成员的函数指针 - 在unique_ptr中用作自定义删除器
- 派生的成员 通过指向基、static_cast、crtp、删除模板的指针
- 删除类成员的动态分配内存的最佳方法是什么
- C++类析构函数删除成员(如果"owner"?
- 在Visual Studio中删除成员std::vector::d ata()
- 为什么删除成员变量的复制构造函数不会阻止默认的复制构造函数
- 队列类中的非空删除成员函数
- 基于模板参数删除成员
- C++11 中已删除成员函数的确切语义是什么?
- 在C++中正确删除成员数组
- C++删除成员函数中的临时节点
- 在c++中,从结构体中删除成员会产生错误
- 如何删除成员函数中的成员数组,以便重新分配
- 状态设计模式 - 不想删除成员类中的此指针