首页 > 解决方案 > 浅层和深层析构函数?

问题描述

想象一个列表“a”,并且有一个用于执行深度复制的列表的复制构造函数。如果“b”是从“a”深度复制的列表,那么两者都可以使用简单的析构函数销毁。这个析构函数应该使用深度破坏。

typedef struct list { void * first; struct list * next } list;

struct list * list_copy_constructor(const struct list * input)
REQUIRE_RETURNED_VALUE_CAPTURE;

void list_destructor(struct list * input);

现在假设您将列表的复制构造函数重命名为列表的深复制构造函数,并为列表添加另一个浅复制构造函数。

/**  Performs shallow copy. */
struct list * list_shallow_copy_constructor(const struct list * input)
REQUIRE_RETURNED_VALUE_CAPTURE;

/**  Performs deep copy. */
struct list * list_deep_copy_constructor(const struct list * input)
REQUIRE_RETURNED_VALUE_CAPTURE;

/**  Be warned performs deep destruction. */
void list_destructor(struct list * input);

执行深度破坏的析构函数可以与深度复制构造函数调用配对使用。

一旦您对列表使用了浅拷贝构造函数,您将需要知道两个列表中的哪一个拥有元素,然后可以使用析构函数销毁其中一个列表(拥有元素的列表),但对于没有的列表'不拥有元素,在销毁拥有元素的列表之前,我需要使用我需要创建的浅析构函数来销毁它。

/**  Performs shallow copy. */
struct list * list_shallow_copy_constructor(const struct list * input)
REQUIRE_RETURNED_VALUE_CAPTURE;

/**  Performs deep copy. */
struct list * list_deep_copy_constructor(const struct list * input)
REQUIRE_RETURNED_VALUE_CAPTURE;

/**  Performs shallow destruction. */
void list_shallow_destructor(struct list * input);

/**  Performs deep destruction. */
void list_deep_destructor(struct list * input);

但是,问题是,我不承认浅析构函数是参考书目中的一个术语,所以我认为我可能做错了什么。难道我做错了什么?例如,我是否应该已经使用智能指针而不是深浅析构函数?

标签: cmemory-managementdynamic-memory-allocationallocation

解决方案


深或浅的概念只存在于程序员的头脑中,而在 C++ 中则非常随意。默认情况下,当对象被销毁时,原始指针成员不会被深度销毁,您可以将其称为浅表,但您可以在对象析构函数中编写额外的代码来深度销毁。另一方面,任何具有析构函数的成员都会调用它们的析构函数,你可能会称之为 deep,并且没有办法避免这种情况。完全相同的机制适用于默认复制和分配,因此同样不可能说一个对象是完全深复制或浅复制或一目了然。

所以区别实际上不是对象析构函数的属性,而是它们的成员。

当然,现在的问题又是关于 C 的,但仍然提到了智能指针。在 C 语言中,您必须决定要实现什么理念,因为没有破坏的概念。如果您遵循类似 C++ 的理念,即为每种类型的成员提供破坏函数,并让它们进行深度调用。

话虽如此,您可能会考虑多种策略,这些策略可能会产生更精简的模型:

如果 /all/ 特定容器的成员是拥有的或 /all/ 不拥有的,那么容器中用于是否销毁 /all/ 子项的简单标志是一个适当的模型。

如果 /all/ 对象与另一个容器共享,或者这可能是特定内容集的最后一个/唯一这样的容器,您可以保留共享容器的循环列表。当析构函数意识到它是最后一个可以销毁 /all/ 内容的容器时。另一方面,您可以简单地使用 shared_ptr 来实现这个模型到一个容器实例,当最后一个指针被释放时,容器就会被销毁。

如果容器中的单个项目可以以任意方式共享,则使其成为每个内容项目的 shared_ptr 的容器。这是最强大的模型,但可能会在内存使用方面产生成本。最终,某个地方需要一个引用计数(尽管循环引用列表也很好,但跨线程互斥要困难得多)在 C++ shared_ptr 中,这是使用存根实现的,但在您自己的 C 对象中,这可能是子对象中的计数器成员。


推荐阅读