std :: vector - 游戏循环中的优化

时间:2015-06-30 21:15:28

标签: c++

我只是对我的设计优化提出了一些问题。

游戏中的所有游戏对象都继承自基类

class Environment;

游戏迭代向量并更新并呈现每个对象:

for (auto& env : this->listEnvironment)
{
    if (env->GetIsMarkedForDeletion()==false)
    {
        env->Update();
        env->Render();
    }
}

只要该对象未标记为删除。

所以这就是我想知道的,最好是创建一个单独的循环并从矢量中删除所有标记为删除的对象,只需将它们留在向量中并且不要渲染他们或者我应该在与渲染相同的循环中进行吗?

根据我的理解,如果我在循环中调整矢量大小,性能会下降很多,但我可能误解了这一点。

1 个答案:

答案 0 :(得分:2)

这是一种方法,几乎​​可以为您的环境清单保持清洁:

编辑2: 可能和它一样高效。感谢评论中的灵感:

struct Environment {
    virtual bool GetIsMarkedForDeletion() const;
    virtual void Render() const;
    virtual void Update();
};

struct World {

    using environment_container = std::vector<std::unique_ptr<Environment>>;
    environment_container listEnvironment;

    static bool is_removable(const environment_container::value_type& ptr)
    {
        return ptr->GetIsMarkedForDeletion();
    }

    void do_update_and_render()
    {
        listEnvironment.erase(std::remove_if(begin(listEnvironment),
                                        end(listEnvironment),
                                        is_removable),
                              end(listEnvironment));

        for (auto& env : this->listEnvironment)
        {
                env->Update();
                env->Render();
        }
    }
};

编辑:回应AlchemicalApples&#39;关注内存碎片,提供了版本2,除非环境的大小超出其高水位,否则不会释放内存:

struct Environment {
    virtual bool GetIsMarkedForDeletion() const;
    virtual void Render() const;
    virtual void Update();
};

struct World {

    using environment_container = std::vector<std::unique_ptr<Environment>>;
    environment_container listEnvironment;
    environment_container survivingEnvironment; // = {}

    void do_update_and_render()
    {
        if (survivingEnvironment.capacity() < listEnvironment.size()) {
            survivingEnvironment.reserve(listEnvironment.size());
        }
        for (auto& env : this->listEnvironment)
        {
            if (env->GetIsMarkedForDeletion()==false)
            {
                env->Update();
                env->Render();
                survivingEnvironment.push_back(move(env));
            }
        }
        survivingEnvironment.swap(listEnvironment);
        survivingEnvironment.clear();   // note-does not clear memory so fragmentation is prevented
    }
};

原作是为了比较:

struct Environment {
    virtual bool GetIsMarkedForDeletion() const;
    virtual void Render() const;
    virtual void Update();
};

struct World {

    using environment_container = std::vector<std::unique_ptr<Environment>>;
    environment_container listEnvironment;

    void do_update_and_render()
    {
        environment_container new_objects;
        new_objects.reserve(listEnvironment.size());
        for (auto& env : this->listEnvironment)
        {
            if (env->GetIsMarkedForDeletion()==false)
            {
                env->Update();
                env->Render();
                new_objects.push_back(move(env));
            }
        }
        swap(new_objects, listEnvironment);
    }
};

版本在就地进行更新,而不分配可能很大的新向量:

void do_update_and_render_in_place()
{
    auto cursor = this->listEnvironment.begin();
    auto sentry = this->listEnvironment.end();
    while(sentry != cursor)
    {
        auto &element = **cursor;
        if(element.GetIsMarkedForDeletion()) { break; }
        element.Update();
        element.Render();
        ++cursor;
    }
    if(sentry == cursor) { return; }
    auto trailing = cursor; // beginning of deleted elements
    ++cursor;
    for(; sentry != cursor; ++cursor) {
        auto &element = **cursor;
        if(false == element.GetIsMarkedForDeletion()) { continue; }
        element.Update();
        element.Render();
        swap(*cursor, *trailing);
        ++trailing;
    }
    this->listEnvironment.erase(trailing, sentry);
}