我们有一个My_list类,它有一个指向Abstract_things的指针列表。为了优化内存使用,所有派生的东西都使用一个使用“new and delete”构造型建立的内存池。为了在启动应用程序期间正确调整池的大小,构建器会确定哪个Thing最大,并根据该大小调整池的大小。
设计困境是如果在模型中添加了新的Thing(用红色Thing_4表示),设计师必须知道转到Builder来调整逻辑。我观察到我们的团队很难记住这样做(大约一半的事情没有在Builder中考虑过)。我非常担心后代会忽视这一点。
我的问题是如何改善这一点?如果在创建Thing_4类的行为中,所有max_size内容都会自动处理,那将是非常好的。我想不出办法。
注意:查看我的图片我意识到这是一个错误。代码框中的最后一行应该是Abstract_thing :: set_max_pool_size(max_size,max_number)。
编辑:我无法弄清楚如何显示图片。预览窗口中的所有内容都很好看,但是在发布时它并不存在。有什么帮助吗?
编辑:为了提供更多背景知识,这是安全关键系统中嵌入式应用程序设计的一部分。我们被允许在应用程序初始化时从堆中分配内存,但是在我们退出初始化阶段之后,可以分配NO动态内存。尝试这样做会导致应用程序崩溃。因此,我们编程为最大的大小和我们使用的最大实例数。让一个池包含足够的空间用于所有派生对象是比为每个派生对象提供池的更好方法。
alt text http://img262.imageshack.us/img262/4470/designproblemof1.png
答案 0 :(得分:3)
已更新:确定...嵌入式系统要求有所改变。
您可以使用类自动注册派生类,然后将此类的静态实例添加到每个派生类。你仍然需要记住这样做,但至少它是自包含在一个地方。
类似的东西:
template<class T>
class RegisterPoolClass
{
public:
RegisterPoolClass() { init_pool.Register(sizeof(T)); }
};
class Thing_1 : public Abstract_Thing
{
static RegisterPoolClass<Thing_1> sInitializer;
...
};
RegisterPoolClass<Thing_1> Thing_1::sInitializer;
您可以使用宏来封装每个派生类所需的代码,就像ATL一样。
答案 1 :(得分:0)
我不确定我是否正确理解这一点,但是什么阻止你进行一个枚举所有派生类的构建步骤,估计它们的大小,无论你现在用什么方式来计算你的东西的大小,并找到最大的一个?
答案 2 :(得分:0)
grep for classes,构建一个测试所有大小的应用程序,如果它们搞砸了就会失败。
echo '#include"head"' > out.cpp
grep "class \w+ : TheClass" *.cpp | sed "s/.*class \(\w\)+ : TheClass.*/assert(sizeof($1) <= MAX_SIZE); >> out.cpp
echo '#include"tail"' >> out.cpp
gcc out.cpp
./a.out
答案 3 :(得分:0)
这个怎么样:
AbstractThing.h#ifndef ABSTRACT_THING
#define ABSTRACT_THING
class AbstractThing
{
private:
static size_t maxChildSize;
static bool maxChildLock;
static std::vector<type_info> validChildren;
static size_t getMaxChildSize()
{
maxChildLock = true;
return maxChildSize;
}
public:
template<typename T>
static void setChildSize()
{
// This is to stop registering things after getMaxChildSize()
// has been called. This check is only needed during testing
if (maxChildLocked)
{
exit(1);
}
maxChildSize = std::max(maxChildSize,sizeof(T));
validChildren.push_back(typeid T);
}
template<typename T>
static bool testValidType()
{
// While testing call this method.
// Don't call in production to speed things up.
// Only registered children will be allowed to get memory.
// Or maybe generate a warning in the log if it fails.
return validChildren.find(typeid T) != validChildren.end();
}
};
template<typename T>
class RegisterAbsoluteThing
{
public:
RegisterAbsoluteThing()
{
AbstractThing::setChildSize<T>();
}
};
#endif
Thing1.h
#ifndef THING_1
#define THING_1
#include "AbstractThing.h"
class Thing1: public AbstractThing
{
};
namespace
{
// Because this is in an anonymous namespace
// It does not matter how many times different files it is included
// This will then all be registered at startup before main.
RegisterAbsoluteThing<Thing1> RegisterAsValidThing1;
// All class that derive from AbstractThing should have this block.
// Any that do not that try and use the pool will cause the tests to fail.
}
#endif
答案 4 :(得分:0)
您是否可以使用CTAGS或类似的解析器来提取所有派生类的名称并使用它来自动生成init_pool实现?