简体   繁体   English

在容器中使用智能指针的原因

[英]Reason for using smart pointers with a container

Simply written I would like to ask "what is a good reason to use smart pointers?"简单写我想问“使用智能指针的好理由是什么?” for ex std::unique_ptr对于前std::unique_ptr

However, I am not asking for reasons to use smart pointers over regular (dumb) pointers .但是,我并不是在询问使用智能指针而不是常规(哑)指针的原因。 I think every body knows that or a quick search can find the reason.我想每个人都知道,或者快速搜索可以找到原因。

What I am asking is a comparison of these two cases:我要问的是这两种情况的比较:

Given a class (or a struct) named MyObject use给定一个名为MyObject的 class (或结构)使用

  1. std:queue<std::unique_ptr<MyObject>>queue;

rather than而不是

  1. std:queue<MyObject> queue;

(it can be any container, not necessarily a queue) (可以是任何容器,不一定是队列)

Why should someone use option 1 rather than 2?为什么有人应该使用选项 1 而不是 2?

That is actually a good question.这实际上是一个好问题。

There are a few reasons I can think of:我能想到的原因有几个:

  • Polymorphism works only with references and pointers, not with value types.多态性仅适用于引用和指针,不适用于值类型。 So if you want to hold derived objects in a container you can't have std::queue<MyObject> .因此,如果您想将派生对象保存在容器中,则不能拥有std::queue<MyObject> One options is unique_ptr , another is reference_wrapper一个选项是unique_ptr ,另一个是reference_wrapper

  • the contained objects are referenced (*) from outside of the container.包含的对象从容器外部引用 (*)。 Depending on the container, the elements it holds can move , invalidating previous references to it.根据容器的不同,它包含的元素可以移动,从而使之前对它的引用无效。 For instance std::vector::insert or the move of the container itself.例如std::vector::insert或容器本身的移动。 In this case std::unique_ptr<MyObject> assures that the reference is valid, regardless of what the container does with it (ofc, as long as the unique_ptr is alive).在这种情况下, std::unique_ptr<MyObject>确保引用是有效的,不管容器对它做了什么(ofc,只要unique_ptr是活动的)。
    In the following example in Objects you can add a bunch of objects in a queue.在下面的Objects示例中,您可以在队列中添加一堆对象。 However two of those objects can be special and you can access those two at any time.但是,其中两个对象可能是特殊的,您可以随时访问这两个对象。

     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(); } };

(*) I use "reference" here with its english meaning, not the C++ type. (*) 我在这里使用“参考”的英文含义,而不是 C++ 类型。 Any way to refer to an object (eg via a raw pointer)引用 object 的任何方式(例如通过原始指针)

Usecase: You want to store something in a std::vector with constant indices, while at the same time being able to remove objects from that vector.用例:您希望将某些内容存储在具有常量索引的std::vector中,同时能够从该向量中删除对象。

If you use pointers, you can delete a pointed to object and set vector[i] = nullptr , (and also check for it later) which is something you cannot do when storing objects themselves.如果你使用指针,你可以删除一个指向 object 并设置vector[i] = nullptr ,(并且稍后检查它)这是你在存储对象本身时不能做的事情。 If you'd store Objects you would have to keep the instance in the vector and use a flag bool valid or something, because if you'd delete an object from a vector all indices after that object's index change by -1.如果您要存储对象,则必须将实例保留在向量中并使用标志bool valid或其他东西,因为如果您要从向量中删除 object,则该对象的索引更改为 -1 后的所有索引。


Note: As mentioned in a comment to this answer, the same can be archieved using std::optional , if you have access to C++17 or later.注意:如对此答案的评论中所述,如果您有权访问 C++17 或更高版本,则可以使用std::optional进行归档。

The first declaration generates a container with pointer elements and the second one generates pure objects.第一个声明生成一个带有指针元素的容器,第二个声明生成纯对象。

Here are some benefits of using pointers over objects:以下是在对象上使用指针的一些好处:

  1. They allow you to create dynamically sized data structures.它们允许您创建动态大小的数据结构。
  2. They allow you to manipulate memory directly (such as when packing or unpacking data from hardware devices.)它们允许您直接操作 memory(例如在从硬件设备打包或解包数据时。)
  3. They allow object references(function or data objects)它们允许 object 引用(函数或数据对象)
  4. They allow you to manipulate an object(through an API) without needing to know the details of the object(other than the API.)它们允许您操作对象(通过 API),而无需了解对象的详细信息(API 除外。)
  5. (raw) pointers are usually well matched to CPU registers, which makes dereferencing a value via a pointer efficient. (原始)指针通常与 CPU 寄存器很好地匹配,这使得通过指针解引用值变得高效。 (C++ “smart” pointers are more complicated data objects.) (C++“智能”指针是更复杂的数据对象。)

Also, polymorphism is considered as one of the important features of Object-Oriented Programming.此外,多态性被认为是面向对象编程的重要特征之一。 In C++ polymorphism is mainly divided into two types: C++中的多态性主要分为两种:

  • Compile-time Polymorphism编译时多态性

This type of polymorphism is achieved by function overloading or operator overloading.这种类型的多态性是通过 function 重载或运算符重载来实现的。

  • Runtime Polymorphism运行时多态性

This type of polymorphism is achieved by Function Overriding which if we want to use the base class to use these functions, it is necessary to use pointers instead of objects.这种类型的多态性是通过 Function 覆盖实现的,如果我们想使用基础 class 来使用这些函数,则必须使用指针而不是对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM