简单地写成,我想问"使用智能指针的好理由是什么? 对于前std::unique_ptr
但是,我并不是在询问使用智能指针而不是常规(哑(指针的理由。我想每个人都知道这一点,或者快速搜索可以找到原因。
我要问的是这两种情况的比较:
给定一个名为MyObject
使用的类(或结构(
std:queue<std::unique_ptr<MyObject>>queue;
而不是
std:queue<MyObject> queue;
(它可以是任何容器,不一定是队列(
为什么有人应该使用选项 1 而不是 2?
这实际上是一个很好的问题。
我能想到的有几个原因:
-
多态性仅适用于引用和指针,不适用于值类型。因此,如果要将派生对象保存在容器中,则不能
std::queue<MyObject>
。一种选择是unique_ptr
,另一种是reference_wrapper
-
包含的对象从容器外部引用 (*(。根据容器的不同,它所包含的元素可以移动,从而使以前对它的引用无效。例如
std::vector::insert
或容器本身的移动。在这种情况下,std::unique_ptr<MyObject>
确保引用是有效的,无论容器如何处理它(ofc,只要unique_ptr
处于活动状态(。
在下面的Objects
示例中,您可以在队列中添加一堆对象。但是,其中两个对象可能是特殊的,您可以随时访问这两个对象。struct MyObject { MyObject(int); }; struct Objects { std::queue<std::unique_ptr<MyObject>> all_objects_; MyObject* special_object_ = nullptr; MyObject* secondary_special_object_ = nullptr; void AddObject(int i) { all_objects_.emplace(std::make_unique<MyObject>(i)); } void AddSpecialObject(int i) { auto& emplaced = all_objects_.emplace(std::make_unique<MyObject>(i)); special_object_ = emplaced.get(); } void AddSecondarySpecialObject(int i) { auto& emplaced = all_objects_.emplace(std::make_unique<MyObject>(i)); secondary_special_object_ = emplaced.get(); } };
(*(我在这里使用的"参考"是英文意思,而不是C++类型。引用对象的任何方式(例如,通过原始指针(
用例:您希望在具有常量索引的std::vector
中存储某些内容,同时能够从该向量中删除对象。
如果使用指针,则可以删除指向的对象并设置vector[i] = nullptr
,(稍后还要检查它(,这是存储对象本身时无法执行的操作。如果你存储对象,你必须将实例保留在向量中并使用标志bool valid
或其他东西,因为如果你从向量中删除一个对象,那么该对象的索引后的所有索引都会改变 -1。
注意:如此答案的评论中所述,如果您可以访问 C++17 或更高版本,则可以使用std::optional
进行存档。
第一个声明生成一个包含指针元素的容器,第二个声明生成纯对象。
以下是在对象上使用指针的一些好处:
- 它们允许您创建动态大小的数据结构。
- 它们允许您直接操作内存(例如在打包或 从硬件设备解压缩数据。
- 它们允许对象引用(函数或数据对象(
- 它们允许您操作对象(通过 API(,而无需知道对象的详细信息(API 除外(。
- (原始(指针通常与 CPU 寄存器匹配良好,这使得通过指针取消引用值非常有效。(C++"智能"指针是更复杂的数据对象。
此外,多态性被认为是面向对象编程的重要特征之一。 在C++多态性主要分为两种类型:
- 编译时多态性
这种类型的多态性是通过函数重载或运算符重载实现的。
- 运行时多态性
这种类型的多态性是通过函数覆盖实现的,如果我们想使用基类来使用这些函数,就必须使用指针而不是对象。