单例模式与迭代器失效

单例模式

#include <iostream>
#include <vector>
#include <mutex>
using namespace std;
mutex mtx;
class singleton {
public:
    shared_ptr<singleton> getInstance() {
        if (only_ = nullptr) {
            unique_lock<mutex> lock(mtx);
            {
                only_ = make_shared<singleton>();
            }
        }
        return only_;
    }

    void dosomething() {
        cout << "do something ..." << "\n";
    }

private:
    singleton() = default;
    ~singleton() = default;
    singleton(const singleton&) = delete;
    singleton& operator=(const singleton&) = delete;
    shared_ptr<singleton> only_;
};

注意的几个问题:

  1. public 中开放的是获取实例的函数,和 dosomething
  2. 将构造函数以及其他,和实例指针(引用)存放在 private
  3. 为了线程安全最好在创建实例时上锁

迭代器失效的情况

要求: 找到一个数组中的奇数,并全部删除

应该用双指针,但是他考察的是迭代器失效的情景,也就是 erase 返回的是下一个迭代器

迭代器版本

#include <iostream>
#include <vector>
namespace  test {
    using namespace std;
    void test1() {
        vector<int> v = {1, 2, 3, 4, 5};
        for (auto it = v.begin(); it != v.end();) {
            if (*(it) & 1) {
                it = v.erase(it);
            } else {
                ++it;
            }
        }
        ranges::for_each(v.begin(), v.end(), [](int i) { std::cout << i << " "; });
    }
}
int main() {
    test::test1();
}

左右指针:

#include <iostream>
#include <vector>
namespace  test {
    using namespace std;
    void test1() {
        vector<int> v = {1, 2, 3, 4, 5};
        int l = 0, r = v.size() - 1;
        while (l <= r) {
            if (!v.at(l) & 1) {
                ++l;
            } else if (v.at(r) & 1) {
                --r;
            } else {
                swap(v[l], v[r]);
                ++l;
                --r;
            }
        }
        v.resize(l);
        ranges::for_each(v.begin(), v.end(), [](int i) { std::cout << i << " "; });
    }
}
int main() {
    test::test1();
}

两种方法的比较:

方法时间复杂度空间复杂度适用场景优点缺点
左右指针 + resizeO(n)O(1)适用于不关心元素顺序的情况高效,只需一次遍历会改变元素的相对顺序
erase 逐个删除O(n²)(最坏情况)O(1)适用于需要保持顺序的情况保持原有顺序删除操作导致元素移动,效率较低

<think>嗯,用户想用C++实现一个怪物自动掉血的游戏逻辑,涉及类设计、工厂模式、单例模式和链表结构。首先,我需要理清各个部分的需求和如何组合在一起。 首先,类设计方面,可能需要一个基类Monster,然后派生出不同类型的怪物,比如普通怪物和精英怪物。基类里应该有共同的方法,比如掉血Update()和显示信息Display()。派生类可以覆盖这些方法,实现不同的行为。 然后,工厂模式。用户提到工厂模式,可能需要一个怪物工厂类来创建不同类型的怪物。工厂模式可以帮助解耦对象的创建和使用,这样添加新怪物类型时不需要修改客户端代码。这里可能需要一个枚举来区分怪物类型,比如MonsterType,然后在工厂类里根据类型生成对应的派生类实例。 单例模式方面,用户可能希望工厂类是一个单例,确保全局只有一个工厂实例。单例模式的实现需要注意线程安全,但在C++中,如果使用局部静态变量,C++11之后是线程安全的,所以可以用这种方法来实现。 接下来是链表结构,用来管理所有的怪物实例。可能需要一个链表来存储所有怪物的指针,方便遍历和操作。这里可以用标准库中的std::list,或者自己实现链表节点。考虑到用户可能希望演示链表的使用,或许应该自己实现一个简单的链表结构,包含添加、删除和遍历的方法。 自动掉血功能,应该有一个游戏循环,每隔一段时间调用怪物的Update()方法,减少血量。这里可能需要使用定时器或者循环中的延时,但具体实现可能依赖于游戏引擎或平台。在示例代码中,可以用简单的循环和sleep来模拟。 另外,用户提到的引用中有关于单例模式的实现,需要静态类属性和方法。参考引用[1],单例模式需要静态方法和静态实例变量。所以工厂类作为单例,应该有一个静态的获取实例的方法,并且构造函数私有化。 引用[4]提到万能引用和右值引用,但在这个问题中可能不直接相关,不过需要注意移动语义或者完美转发是否在工厂创建对象时有用,但可能这里暂时不需要。 综合以上,设计步骤大致如下: 1. 定义Monster基类,包含虚方法Update和Display。 2. 派生NormalMonster和EliteMonster,实现不同的掉血逻辑。 3. MonsterFactory作为单例工厂,根据类型创建怪物对象。 4. 使用链表来管理所有怪物,可能用std::list或者自定义链表。 5. 游戏主循环中定期调用每个怪物的Update,并显示状态。 需要注意内存管理,比如使用智能指针还是原始指针。在示例代码中,可能使用原始指针,但需要确保在链表删除时释放内存,防止泄漏。 测试部分,可能需要创建几个怪物,添加到链表,然后运行循环观察血量变化。 可能的问题点:单例工厂的线程安全,链表遍历时的删除操作是否会导致迭代器失效。如果使用标准库的链表,删除元素时需要注意迭代器的有效性,但在示例中可能简化处理,比如在Update后不立即删除,而是标记为死亡,在下一次循环中清理。 另外,自动掉血的时间间隔如何实现。在控制台程序中,可以用sleep函数,但实际游戏开发中会用游戏时钟或delta time来计算。 现在把这些思路整理成代码结构,并确保各部分协调工作。比如,工厂创建怪物后加入链表,游戏循环遍历链表调用Update,当怪物血量<=0时从链表中移除并删除对象。 最后,考虑用户可能需要的扩展性,比如通过工厂模式添加新怪物类型,或者通过单例方便全局访问工厂实例。</think># C++实现怪物自动掉血系统设计指南 ## 一、核心类设计 ### 1.1 基类派生类 ```cpp class Monster { protected: int health; std::string name; public: Monster(int h, const std::string& n) : health(h), name(n) {} virtual void Update() = 0; // 纯虚函数实现多态 virtual void Display() const { std::cout << name << " HP: " << health << std::endl; } virtual ~Monster() = default; }; class NormalMonster : public Monster { public: NormalMonster() : Monster(100, "普通怪物") {} void Update() override { health -= 5; // 每秒掉5点血 } }; class EliteMonster : public Monster { public: EliteMonster() : Monster(200, "精英怪物") {} void Update() override { health -= 3; // 每秒掉3点血 if (health < 50) health -= 7; // 低血量时加速掉血 } }; ``` ## 二、设计模式实现 ### 2.1 单例模式工厂类 ```cpp class MonsterFactory { private: MonsterFactory() = default; static MonsterFactory* instance; public: enum MonsterType { NORMAL, ELITE }; static MonsterFactory* GetInstance() { if (!instance) instance = new MonsterFactory(); return instance; } Monster* CreateMonster(MonsterType type) { switch(type) { case NORMAL: return new NormalMonster(); case ELITE: return new EliteMonster(); default: return nullptr; } } }; MonsterFactory* MonsterFactory::instance = nullptr; // 静态成员初始化 ``` > 单例模式通过静态成员变量确保全局唯一实例[^1] ### 2.2 对象管理链表 ```cpp class MonsterList { private: struct Node { Monster* data; Node* next; Node(Monster* m) : data(m), next(nullptr) {} }; Node* head = nullptr; public: void Add(Monster* m) { Node* newNode = new Node(m); newNode->next = head; head = newNode; } void UpdateAll() { Node* curr = head; while(curr) { curr->data->Update(); curr = curr->next; } } void RemoveDead() { Node** curr = &head; while(*curr) { if ((*curr)->data->health <= 0) { Node* temp = *curr; *curr = temp->next; delete temp->data; delete temp; } else { curr = &((*curr)->next); } } } }; ``` ## 三、系统集成 ```cpp int main() { MonsterFactory* factory = MonsterFactory::GetInstance(); MonsterList list; list.Add(factory->CreateMonster(MonsterFactory::NORMAL)); list.Add(factory->CreateMonster(MonsterFactory::ELITE)); while(true) { list.UpdateAll(); list.RemoveDead(); std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; } ``` #
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值