C++多态场景下raw pointer与smart pointer使用问题咨询
现有代码可优化点
你当前的基类Item缺少虚析构函数,会导致std::unique_ptr<Item>销毁对象时仅调用基类析构,派生类Weapon的资源无法正确释放,建议补充:
class Item { // ... 原有代码 public: virtual ~Item() = default; };
问题1:多态是否与智能指针兼容?
完全兼容,C++标准库的智能指针原生支持多态场景。你当前使用std::unique_ptr<Item>存储Weapon实例的写法是合法的,虚函数调用也会按多态规则正常分发,没有兼容性问题。
问题2:返回raw pointer是唯一的可行方案吗?
不是,可行方案取决于你是否要转移对象的所有权:
- 如果你只是临时访问对象、不改变所有权归属:返回裸指针是完全合法的,
std::unique_ptr::get()的设计目的就是提供观测用的裸指针,只要你能保证访问期间vector内的对应元素没有被销毁即可。除此之外你也可以返回引用、std::reference_wrapper等观测类型。 - 如果你需要把对象的所有权从
vector转移到调用方:可以把vector内的unique_ptrmove出来返回,示例实现如下:
std::unique_ptr<Weapon> getAnElement_uniquePointer(int i) { if (i < 0 || i >= elements.size()) return nullptr; if (auto* wp = dynamic_cast<Weapon*>(elements[i].get())) { // 转移所有权 auto item_ptr = std::move(elements[i]); elements.erase(elements.begin() + i); // 可选:移除vector内的空指针占位 return std::unique_ptr<Weapon>(static_cast<Weapon*>(item_ptr.release())); } return nullptr; }
注意这种场景下,返回后vector内就不再持有该对象的所有权了。
问题3:如果需要在vector和程序其他模块同时使用对象,是否必须使用shared_ptr?
不是绝对的,分两种情况:
- 如果你可以保证
vector的生命周期一定长于所有使用该对象的模块:可以继续用std::unique_ptr存储,其他模块用裸指针/引用访问即可,性能更高也不需要维护引用计数。 - 如果对象的生命周期不确定,可能出现
vector先销毁、其他模块仍要访问对象的情况:必须使用std::shared_ptr实现共享所有权,必要时可以配合std::weak_ptr避免循环引用问题。
问题4:是否有方法返回引用类型的查询结果?
有,但是C++的引用不允许为空,所以你需要提前处理查询失败的场景(下标越界、类型不匹配等),两种常用实现:
- 异常模式:查询失败抛异常,成功返回引用
Weapon& getAnElement_ref(int i) { if (i < 0 || i >= elements.size()) throw std::out_of_range("下标越界"); if (auto* wp = dynamic_cast<Weapon*>(elements[i].get())) { return *wp; } throw std::bad_cast(); }
- 可选值模式(C++17及以上支持):用
std::optional包装引用,查询失败返回空
#include <optional> #include <functional> std::optional<std::reference_wrapper<Weapon>> getAnElement_optional_ref(int i) { if (i < 0 || i >= elements.size()) return std::nullopt; if (auto* wp = dynamic_cast<Weapon*>(elements[i].get())) { return std::ref(*wp); } return std::nullopt; }
使用时判断optional是否有值即可,不需要处理异常。
内容的提问来源于stack exchange,提问作者Studio Albert
相关产品推荐
相关产品推荐

