3

我们有一个 My_list 类,它有一个指向 Abstract_things 的指针列表。为了优化内存使用,所有派生的事物都使用一个以“新建和删除”原型建立的内存池。为了在应用程序初始化期间正确调整池的大小,构建器会确定哪个事物是最大的,并以此为基础调整池的大小。

设计困境是,如果向模型中添加了新事物(用红色的 Thing_4 表示),设计者必须知道转到 Builder 来调整逻辑。我观察到我们的团队很难记住这样做(大约一半的事情没有在 Builder 中考虑)。我非常担心后代会忽略这一点。

我的问题是如何改善这一点?如果在创建 Thing_4 类的过程中,自动处理所有 max_size 的东西,那就太好了。不过我想不出办法。

注意:查看我的照片我意识到有一个错误。代码框中的最后一行应为 Abstract_thing::set_max_pool_size(max_size, max_number)。

编辑:我不知道如何显示图片。预览窗口中的一切看起来都不错,但发布时却不存在。有什么帮助吗?

编辑:为了提供更多背景知识,这是安全关键系统中嵌入式应用程序设计的一部分。当应用程序初始化时,我们可以在堆外分配内存,但是在我们退出初始化阶段后,就不能分配动态内存了。尝试这样做会使应用程序崩溃。因此,我们编程到最大尺寸和我们使用的最大实例数。拥有一个包含所有派生对象的足够空间的池是比为每个派生对象拥有一个池更好的方法。

替代文字 http://img262.imageshack.us/img262/4470/designproblemof1.png

4

5 回答 5

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 相同的方式封装每个派生类中所需的代码。

于 2008-11-12T00:42:31.867 回答
0

我不确定我是否理解正确,但是是什么阻止了您进行枚举所有派生类的构建步骤,以您现在使用的任何方式估计它们的大小来计算您的东西的大小,并找到最大的一个?

于 2008-11-12T00:38:52.700 回答
0

grep 类,构建一个测试所有大小的应用程序,如果它们搞砸了就会失败。

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
于 2008-11-12T00:43:56.077 回答
0

这个怎么样:

抽象事物.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
东西1.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
于 2008-11-12T00:44:52.377 回答
0

您可以使用 CTAGS 或类似的解析器来提取所有派生类的名称并使用它来自动生成您的 init_pool 实现吗?

于 2008-11-12T01:50:31.823 回答