问题很简单。我有一个可以构造如下的类:
class MyClass {
struct A {
// ...
};
struct B {
// ...
};
};
问题是:MyClass::B
中的信息在经过一段时间的预计算后是无用的,而MyClass::A
永远不能被删除(程序可能运行了几天(。MyClass::B
包含相当多的信息。我想摆脱MyClass::B
,同时MyClass::A
保持在同一记忆位置。
是否可以在不修改太多数据结构并且不必向MyClass::A
添加任何其他内容(特别是指向MyClass::B
的指针(的情况下执行此操作?如果是这样,实施它的正确方法是什么?考虑到程序必须尽可能节省内存(让我们将其发挥到极致(。我使用 C++14 顺便说一句。
(还有一个额外的问题:是否可以从MyClass
中删除与MyClass::B
对应的块?
首先,或者全部是一个类声明。不能删除类声明的一部分。你可能还有这样的东西:
// The exact place of the declaration doesn't matter actually
class A {...};
class B {...};
class C {
A a;
B b;
};
只需将其更改为使用指针(在当今时代,智能指针,如 std::unique_ptr(:
class C {
A a;
std::unique_ptr<B> b;
void FinishTaskThatRequiredB() {
b.reset(); // calls B::~B() and frees the memory.
}
};
好吧,让我们详细说明一下我写的内容:">要么B的生命与MyClass的生命联系在一起,要么它是独立的。在后一种情况下,您必须以某种方式跟踪它"。
把上下文从问题中放回去:
- MyClass::B 经过一段时间的预计算后毫无用处。
- 我的类::A 绝不能被删除。
因此,您希望以某种方式跟踪它。如何?嗯,这取决于寿命的规则。
- 如果B有时可以存在,有时不依赖于难以控制(或完全不可知(的情况,那么有一个指向它的指针,在它无用时设置为
nullptr
,并在有用时动态分配几乎是唯一的解决方案。
但在这里我们有更多的知识:B首先存在,然后变得无用,并且永远如此。换句话说,在用于创建 A 的一些初始构建步骤之后,您不需要 B。
有一种模式正是这样做的:构建器模式。它的目的是封装一个复杂的构建操作,也许会跟踪一些状态,直到它构建了一些对象,此时它变得无用并且可以被销毁。
class ABuilder
{
public:
setSomeInfo(int);
doSomeComputation(......);
// etc
A get(); /// finalize building of A
private:
int someInfo_ = 0;
};
// somewhere else
auto b = ABuilder();
b.setSomeInfo(42);
b.doSomeComputation(......);
auto a = b.get();
// b is no longer used past that point
// delete it if it was allocated dynamically
// or let it go out of scope if it was automatic
从您的示例中,它会像这样映射:
A
仍然A
.B
ABuilder
.- 不需要
MyClass
。
如果您提供了实际的类名和用途,则更容易使示例有意义;)
无论如何,指针很可能是实现您欲望的关键。无论如何,您也需要将B
与MyClass
分开。您可以避免在MyClass中使用指针(请参阅问题和其他答案的注释(,如果您单独存储B
并反转指针的方向:
class MyClass
{
struct A { };
A a;
};
class Wrapper
{
struct B { };
MyClass* mc;
B b;
};
现在在初始化期间,您将为每个MyClass
创建一个Wrapper
,很可能包含在两个不同的数组中:
MyClass items[NUMBER_OF_ITEMS]; // global array?
Wrapper* wrappers = new Wrapper[NUMBER_OF_ITEMS];
// assign each item to its corresponding wrapper
// use the wrappers for initialisation
delete[] wrappers;
现在剩下的只是一个指针,如果它是单独初始化例程中的局部变量,你甚至可能会摆脱它......