WidgetManager

照例列出WidgetManager的全部家当:


mDelegates 用来存储parse XML的delegate

重头在于

mFactoryList  obsolete

mVectorIUnlinkWidget

mUnlinkWidgets

这里只是大战前的猜测:

mFactoryList 中存放的是IWidgetFactory


重点分析:

引入代码:


这种模式在MyGUI中应该是过时的:

因为关于IWidgetFactory的操作都是

//TODO

正如FactoryManager中提到的Manager类之沟通与子类的协调者,

负责employer之间的注册于与离退,

对于:mUnlinkWidgets 注册,

	void WidgetManager::addWidgetToUnlink(Widget* _widget)
	{
		if (_widget) mUnlinkWidgets.push_back(_widget);
	}

离退:

	void WidgetManager::unlinkFromUnlinkers(Widget* _widget)
	{
		for (VectorIUnlinkWidget::iterator iter = mVectorIUnlinkWidget.begin(); iter!=mVectorIUnlinkWidget.end(); ++iter)
		{
			(*iter)->_unlinkWidget(_widget);
		}
		// вызывать последним, обнулится
		removeWidgetFromUnlink(_widget);
	}


	void WidgetManager::removeWidgetFromUnlink(Widget*& _widget)
	{
		VectorWidgetPtr::iterator iter = std::find(mUnlinkWidgets.begin(), mUnlinkWidgets.end(), _widget);
		if (iter != mUnlinkWidgets.end())
		{
			(*iter) = mUnlinkWidgets.back();
			mUnlinkWidgets.pop_back();
		}
		else
		{
			_widget = nullptr;
		}
	}
对于:mVectorIUnlinkWidget

这个有点儿复杂,是说,对于Widget向每个IUnlinkWidget manager 注册的控件而言,

Widget Manager 使得其退注册。

	void WidgetManager::registerUnlinker(IUnlinkWidget * _unlink)
	{
		unregisterUnlinker(_unlink);
		mVectorIUnlinkWidget.push_back(_unlink);
	}
    unregisterUnlinker

	void WidgetManager::unregisterUnlinker(IUnlinkWidget * _unlink)
	{
		for (size_t pos=0; pos<mVectorIUnlinkWidget.size(); pos++)
		{
			if (mVectorIUnlinkWidget[pos] == _unlink)
			{
				mVectorIUnlinkWidget[pos] = mVectorIUnlinkWidget[mVectorIUnlinkWidget.size()-1];
				mVectorIUnlinkWidget.pop_back();
				break;
			}
		}
	}

离退:

createWidget  创建Widget分两步:

    1)通过FacotryManager 创建Widget

    2)然后再初始化:

        _style, _coord, _align, skin, _parent, _cropeedParent, _creator, _name

    返回 widget

 Widget* WidgetManager::createWidget(WidgetStyle _style, const std::string& _type, const std::string& _skin, const IntCoord& _coord, Align _align, Widget* _parent, ICroppedRectangle * _cropeedParent, IWidgetCreator * _creator, const std::string& _name)

	{
		IObject* object = FactoryManager::getInstance().createObject("Widget", _type);
		if (object != nullptr)
		{
			Widget* widget = object->castType<Widget>();
			ResourceSkin* skin = SkinManager::getInstance().getByName(_skin);
			widget->_initialise(_style, _coord, _align, skin, _parent, _cropeedParent, _creator, _name);

			return widget;
		}

		// старый вариант создания这句的意思是Obsolete 大笑
		for (SetWidgetFactory::iterator factory = mFactoryList.begin(); factory != mFactoryList.end(); ++factory)
		{
			if ((*factory)->getTypeName() == _type)
			{
				Widget* widget = (*factory)->createWidget(_style, _skin, _coord, _align, _parent, _cropeedParent, _creator, _name);
				return widget;
			}
		}

		MYGUI_EXCEPT("factory '" << _type << "' not found");
		return nullptr;
	}

根据以上三点分析:

Widget  至少完成三种职能:

1,被调用来创建Widget 并对其初始化, skin之类的操作

2,被其他Manager(//TODO 在后续拔出后幕)所调用

      来注册,Widget 和 IUnlinkWidget(对于每个manager 而言)



对于Initialize

	void WidgetManager::initialise()
	{
		MYGUI_ASSERT(!mIsInitialise, INSTANCE_TYPE_NAME << " initialised twice");
		MYGUI_LOG(Info, "* Initialise: " << INSTANCE_TYPE_NAME);

		//registerUnlinker(this);

		FactoryManager& factory = FactoryManager::getInstance();

		factory.registerFactory<Button>("Widget");
		factory.registerFactory<Canvas>("Widget");
		factory.registerFactory<ComboBox>("Widget");
		factory.registerFactory<DDContainer>("Widget");
		factory.registerFactory<Edit>("Widget");
		factory.registerFactory<HScroll>("Widget");
		factory.registerFactory<ItemBox>("Widget");
		factory.registerFactory<List>("Widget");
		factory.registerFactory<ListBox>("Widget");
		factory.registerFactory<ListCtrl>("Widget");
		factory.registerFactory<MenuBar>("Widget");
		factory.registerFactory<MenuCtrl>("Widget");
		factory.registerFactory<MenuItem>("Widget");
		factory.registerFactory<Message>("Widget");
		factory.registerFactory<MultiList>("Widget");
		factory.registerFactory<PopupMenu>("Widget");
		factory.registerFactory<Progress>("Widget");
		factory.registerFactory<ScrollView>("Widget");
		factory.registerFactory<StaticImage>("Widget");
		factory.registerFactory<StaticText>("Widget");
		factory.registerFactory<Tab>("Widget");
		factory.registerFactory<TabItem>("Widget");
		factory.registerFactory<VScroll>("Widget");
		factory.registerFactory<Widget>("Widget");
		factory.registerFactory<Window>("Widget");

#ifndef MYGUI_DONT_USE_OBSOLETE

		factory.registerFactory<RenderBox>("Widget");
		factory.registerFactory<Sheet>("Widget");

#endif // MYGUI_DONT_USE_OBSOLETE

		MYGUI_LOG(Info, INSTANCE_TYPE_NAME << " successfully initialized");
		mIsInitialise = true;
	}
FactoryManager 类觉得应该叫WidgetCreateFactoryManager
因为它的职能是用来注册MyGUI 所支持Widget的所用种类:
觉得这里是个亮点,因为全部都是hard code 将来MyGUI插件化肯定是要用来动态加载。
值得一提的是MyGUI 将一些控件该成更人性化。
摘自MyGUI 官网:
http://redmine.mygui.info/repositories/entry/mygui/tags/MyGUI3.2/ChangeLog.txt

 
  
78
-- Widgets --
79

- VScroll and HScroll replaced with single ScrollBar class.
80
- Edit renamed into EditBox.
81
- List renamed into ListBox.
82
- MenuCtrl renamed into MenuControl.
83
- MultiList renamed into MultiListBox.
84
- Progress renamed into ProgressBar.
85
- StaticImage renamed into ImageBox.
86
- StaticText renamed into TextBox.
87
- Tab renamed into TabControl.
88
- New Window property Moveable.
89
- Message moved from Core to Common.
90
- MultiListBox now support different modes of columns resizing.
91
- Button properties StateCheck and ButtonPressed replaced with single property StateSelected.
92
- ListBox and ComboBox now support ToolTip.
93
- Menu items can be checked now, tick icon appears.
94
- Property AlignVert renamed into VerticalAlignment.
95
- Hidden widget lose input and focus.
96
- Active elements visualisation in list now properly respond to changes in the list.
97
- All text related properties was moved from Widget to TextBox.



1. 简答题(每题 5 分,共 15 分) 1. 简述 `std::unique_ptr` 和 `std::shared_ptr` 的主要区别,并指出它们各自适用的典型场景。 答:`std::unique_ptr` 和 `std::shared_ptr`的主要区别是资源权利是否共享。 `std::unique_ptr`离开作用域后自动释放资源,通过其析构函数自动释放资源。 `std::shared_ptr`使用引用计数机制,一个指向资源的`std::shared_ptr`的智能指针离开作用域时,引用计数减1,当最后一个指向资源的`std::shared_ptr`智能指针离开作用域,即引用计数为0时释放资源。 `std::unique_ptr`适用于需要独占资源且出作用域自动释放资源的场景。`std::shared_ptr`适用于共享资源权利的场景,对于多线程共享资源,此种智能指针也是支持的,因为其引用计数使用原子整数来实现。 2. 什么是循环引用?如何避免 `std::shared_ptr` 导致的循环引用? 答:两个或多个`std::shared_ptr`相互引用,形成一个环状态结构,这种情况称为循环引用,最终结果会导致内存泄漏。举例说明 ```cpp struct A{ std::shared_ptr<B> b_; }; struct B{ std::shared_ptr<A> a_; }; void test() { std::shared_ptr<A> pa=std::make_shared<A>(); std::shared_ptr<B> pb=std::make_shared<B>(); pa->b_ = pb; pb->a_ = pa; } ``` 分析test的调用过程,创建两个`std::shared_ptr`智能指针,各自引用计数为1。当给各个成员赋值完成,两个智能指针的引用计数都为2。当出作用域时,pa与pb引用计数都减为1,都没有使得引用计数减为零来释放内存。最终结果形成一个孤立的环。 使用`std::weak_ptr`类型的智能指针,它的创建与销毁不会引起引用计数的增减,且在不打破循环引用的情况,也保证了内存不会泄漏。 3. 解释 `std::enable_shared_from_this` 的作用,并给出一个使用场景。 答:未使用过 2. 判断题(每题 2 分,共 10 分) 判断以下代码是否存在内存泄漏或悬空指针问题,并简要说明理由。 ```cpp std::shared_ptr<int> sp1(new int(10)); std::shared_ptr<int> sp2 = sp1; sp1.reset(); std::cout << *sp2 << std::endl; ``` 答:不会内存泄漏或悬空指针问题,sp1.reset()保证引用计数减1。 ```cpp std::unique_ptr<int> up(new int(5)); auto raw = up.get(); up.reset(); std::cout << *raw << std::endl; ``` 答:有悬空指针问题,up.reset()导致其指向的资源释放,结果就是raw指针悬空。 ```cpp std::shared_ptr<int> sp(new int(20)); std::weak_ptr<int> wp = sp; sp.reset(); if (auto locked = wp.lock()) { std::cout << *locked << std::endl; } ``` 答:不会由内存泄漏或悬空指针问题,在sp.reset()后,sp指向了空指针。调用wp.lock(),由于其由sp而来,sp己指向空指针,因此将返回指向空的`std::shared_ptr`。 3. 选择题(单选,每题 1 分,共 5 分) 1. 使用 `std::make_shared` 相较于 `std::shared_ptr<T>(new T)` 的优势是: C - A. 性能更好,内存分配更高效 - B. 更安全,避免内存泄漏 - C. 支持数组类型 - D. A 和 B 都正确 2. 下列关于 `std::weak_ptr` 的说法正确的是: C - A. 可以直接解引用访问对象 - B. 可以延长对象生命周期 - C. 用于打破 `shared_ptr` 的循环引用 - D. 是线程不安全的 --- 💻 二、编程题(共 70 分) 题目 1:线程安全的对象池(40 分) 要求: 实现一个线程安全的对象池类 `ObjectPool<T>`,满足以下条件: - 使用 `std::unique_ptr<T>` 管理对象生命周期; - 支持自定义 deleter; - 提供 `Acquire()` 和 `Release()` 方法; - 使用互斥锁保证线程安全; - 对象池初始大小为 10,支持动态扩展; - 禁止拷贝构造和赋值操作; - 提供方法 `Size()` 返回当前池中可用对象数量。 示例接口: ```cpp template <typename T> class ObjectPool { public: using Deleter = std::function<void(T*)>; ObjectPool(std::function<std::unique_ptr<T>()> creator, Deleter deleter); std::unique_ptr<T, Deleter> Acquire(); void Release(std::unique_ptr<T, Deleter> obj); size_t Size() const; }; ``` 评分标准: 项目 分值 正确实现对象池逻辑 15 分 使用 `unique_ptr` + 自定义 deleter 10 分 线程安全实现 10 分 禁止拷贝/赋值 2 分 提供 Size() 接口 3 分 ```cpp template <typename T> class ObjectPool { public: using Deleter = std::function<void(T*)>; ObjectPool(std::function<std::unique_ptr<T>()> creator, Deleter deleter) : creator_(creator), deleter_(deleter) { for (int i = 0; i < 10; i++) { objs_.push_back(std::unique_ptr<T, Deleter>(creator_().release())); } } ObjectPool(const ObjectPool&) = delete; ObjectPool& operator=(const ObjectPool&) = delete; std::unique_ptr<T, Deleter> Acquire() { std::unique_lock<std::mutex> lock(lock_); if (objs_.empty()) { objs_.push_back(std::unique_ptr<T, Deleter>(creator_().release())); } auto p = objs_[objs_.size() - 1].release(); objs_.pop_back(); return std::unique_ptr<T, Deleter>(p); } void Release(std::unique_ptr<T, Deleter> obj) { std::unique_lock<std::mutex> lock(lock_); objs_.push_back(obj.release()); } size_t Size() const { std::unique_lock<std::mutex> lock(lock_); return objs_.size(); } private: std::function<std::unique_ptr<T>()> creator_; Deleter deleter_; std::mutex lock_; std::vector<std::unique_ptr<T, Deleter>> objs_; }; ``` --- 题目 2:Qt 内存管理应用题(30 分) 背景: 你正在开发一个 Qt 应用程序,需要管理多个动态创建的 `QWidget` 子类对象(如窗口、按钮等)。这些对象的生命周期由父子关系部分管理,但某些对象需要在特定条件下手动释放。 要求: 1. 设计一个资源管理器类 `WidgetManager`,支持以下功能: - 使用 `QObject` 父子关系管理部分控件; - 使用智能指针(如 `std::unique_ptr` 或 `QSharedPointer`)管理非父子关系的控件; - 提供方法 `CreateWidget()` 创建控件; - 提供方法 `ReleaseWidget()` 手动释放控件; - 提供方法 `PrintMemoryStatus()` 打印当前存活控件数量; 2. 使用 Qt 的内存泄漏检测工具(如 `QML_DEBUG` 或 `valgrind`)验证无内存泄漏; 3. 简要说明你在哪些场景下使用智能指针,哪些场景使用父子关系。 评分标准: 项目 分值 正确设计 WidgetManager 类 10 分 正确结合 QObject 父子关系与智能指针 10 分 提供内存状态打印功能 5 分 使用检测工具验证无泄漏 5 分 --- ```cpp #include <QObject> #include <QWidget> #include <QSet> #include <QMap> #include <QDebug> class WidgetManager : public QObject { Q_OBJECT public: WidgetManager(QObject* parent) : QObject(parent) { } ~WidgetManager() { } WidgetManager(const WidgetManager&) = delete; WidgetManager& operator=(const WidgetManager&) = delete; template<class T> QWidget* CreateWidget(QWidget* parent) { QWidget* widget = new T(parent); if (parent) { haveParentWidgets_.insert(widget); connect(widget, &QObject::destroyed, this, [this, widget]() { haveParentWidgets_.erase(haveParentWidgets_.find(widget)); }); } else { noHaveParentWidgets_[widget] = QSharedPointer<QWidget>(widget); } return widget; } void ReleaseWidget(QWidget* widget) { if (widget->parent()) { auto it = haveParentWidgets_.find(widget); if (it != haveParentWidgets_.end()) { widget->deleteLater(); haveParentWidgets_.erase(it); } } else { auto it = noHaveParentWidgets_.find(widget); if (it != noHaveParentWidgets_.end()) { noHaveParentWidgets_.erase(it); } } } void PrintMemoryStatus() const { qDebug() << "Number of parent-manged widgets:" << haveParentWidgets_.size(); qDebug() << "Number of noparent-managed widets:" << noHaveParentWidgets_.size(); } private: QSet<QWidget *> haveParentWidgets_; QMap<QWidget *, QSharedPointer<QWidget>> noHaveParentWidgets_; }; ``` 智能指针使用在需要此管理器统一管理的控件对象的情况,父子关系用于基于QT自带的机制来管理控件对象的情况。
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值