共享指针是怎么回事?

发布于 2024-12-05 01:28:39 字数 470 浏览 0 评论 0原文

我的程序由于添加了指向向量的指针而失败。经过大量阅读和删除后,我将其更改为将共享指针添加到集合中(使用插入),一开始很好,但现在也失败了。我尝试了两种解决方案;两者都不起作用。其中一个也失败了,而另一种(make共享类型)则无法编译。

阅读更多内容后,我发现了这个 论坛 其中指出,我不应该指向具有两个不同共享指针的对象,而应该创建它的副本。那么共享指针的最大区别是什么......?

My program fails due to addition of a pointer to a vector. After much reading and deleting I have changed it to an addition of a shared pointer into a set (using insert) which was fine at first but now fails as well. I tried two solutions; neither worked. One failed as well and the other, the make shared kind, did not compile.

Reading a bit more I came upon this forum which states, that I shouldn't point to something with two different shared pointers but rather create a copy of it. So what is the big difference of the shared pointer...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赴月观长安 2024-12-12 01:28:39

一切都与所有权有关。如果实体(函数或对象)负责确保删除指针,则该实体(函数或对象)被称为“拥有”指针。每当您使用new时,某人、某处都必须取得返回指针的所有权。如果不是这种情况,则存在内存泄漏。

各种智能指针的目的都是对某种形式的所有权进行建模。智能指针的析构函数是可以触发指针删除的。

std::auto_ptr (只要你不复制它)模型单一所有权。也就是说,任何拥有 auto_ptr 实例的实体都是会导致该指针被破坏的实体。感谢黑客技术,复制 auto_ptr 实际上将所有权从复制的对象转移到要复制到的对象(注意:永远不要这样做)。

所以,如果你有这个:

std::auto_ptr<int> p1 = new int(4);

它肯定会被销毁(只要持有它的实体被正确清理)。当p1脱离堆栈时,指针将被销毁。如果p1是类的成员,那么当该类实例被销毁时,指针将被销毁。指针的生命周期是有范围的。 Boost 实际上有一个不可复制的等效项,称为 boost::scoped_ptr。

使用任何类型的智能指针时都必须遵守几条规则。这是最重要的。

规则#1:如果您从指针构造一个智能指针实例,那么您所说的是,“当前没有对象拥有此指针的所有权。我现在< em>将所有权交给您,即智能指针。”这就是从裸指针构造智能指针对象的含义。

此代码违反了规则 #1:

std::auto_ptr<int> p1 = new int(4);
std::auto_ptr<int> p2 = p1.get();

auto_ptr::get() 函数返回指针,因此这是合法的 C++ 代码(可以编译)。但是,p1p2 现在都认为它们拥有该指针。因为 auto_ptr 仅模型单一所有权,这是不允许的。当p2被销毁时,它将删除该指针。然后,当p1被销毁时,它将尝试删除相同指针。

哎呀。

现在我们已经非常清楚规则#1了,让我们看看shared_ptr。这个智能指针模型共享所有权。多个实体可以同时声明指针的所有权。仅当全部都使用完该指针后,该指针才会被删除。因此,如果 3 个对象都包含同一对象的 shared_ptr,则在删除所有包含 shared_ptr 的三个对象之前,该对象不会被删除。

重要的是要理解 shared_ptr 是一个智能指针。因此,它受规则#1 的约束。

这可能没有道理。毕竟,它应该允许共享所有权。这一定意味着这是允许的,对吧?

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1.get();

没有。这仍然是错误的。 auto_ptrshared_ptr 之间的区别在于,您可以使用 shared_ptr 来执行此操作:

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1;

这是 p2 的复制构造代码>p1。从裸指针创建 shared_ptr 与从现有 shared_ptr 创建共享指针之间存在根本区别。后者实际上是两者之间共享所有权的东西。前者只会造成坏事。

因此,如果您有一个裸指针并将其放入 shared_ptr 中,则只能对该指针执行一次。如果您想共享所有权,则必须复制它。

有一个半后门:enable_shared_from_this。如果您从此类型派生一个类,那么您的类将具有一个 shared_from_this 私有成员,该类的成员函数可使用该成员来转移所有权。所以:

struct Type : public enable_shared_from_this
{
  DoSomething()
  {
    shared_ptr<Type> p2 = shared_from_this();
    FunctionThatTakesOwnership(p2);
  }
};

shared_ptr<Type> p1 = new Type;
p1->DoSomething();

除此之外,您还必须通过显式复制对象来转移所有权。

It's all about ownership. An entity (a function or object) is said to "own" a pointer if it is that entity's job to ensure that the pointer is deleted. Any time you use new, someone, somewhere must take ownership of the pointer returned. If this is not the case, you have a memory leak.

The purpose of all kinds of smart pointers is to model some form of ownership. The destructor of the smart pointer is what can trigger the deletion of the pointer.

std::auto_ptr (as long as you don't copy it) models single-ownership. That is, whatever entity has the auto_ptr instance is the entity that will cause that pointer's destruction. Thanks to hackery, copying an auto_ptr actually transfers ownership from the copied object to the object being copied to (note: never do this).

So, if you have this:

std::auto_ptr<int> p1 = new int(4);

This is guaranteed to be destroyed (so long as the entity holding it is properly cleaned up). When p1 falls off the stack, the pointer will be destroyed. If p1 were a member of a class, then the pointer will be destroyed when that class instance is destroyed. The lifetime of the pointer is scoped. Boost actually has a non-copyable equivalent called boost::scoped_ptr.

There are several rules that you must abide by when using any kind of smart pointers. This is the most important.

Rule #1: If you construct a smart pointer instance from a naked pointer, what you are saying is, "No object currently has ownership of this pointer. I am now giving ownership to you, the smart pointer." That is what it means to construct a smart pointer object from a naked pointer.

This code is a violation of Rule #1:

std::auto_ptr<int> p1 = new int(4);
std::auto_ptr<int> p2 = p1.get();

The auto_ptr::get() function returns the pointer, so this is legal C++ code (it compiles). However, both p1 and p2 now think that they own the pointer. Because auto_ptr only models single-ownership, that is not allowed. When p2 is destroyed, it will delete the pointer. Then, when p1 is destroyed, it will try to delete the same pointer.

Oops.

Now that we're all very clear on Rule #1, let's look at shared_ptr. This smart pointer models shared ownership. Multiple entities can claim ownership of the pointer at the same time. The pointer will only be deleted when all of them are finished using it. So if 3 objects all contain a shared_ptr to the same object, that object will not be deleted until all three that contain the shared_ptr are deleted.

It is important to understand that shared_ptr is a smart pointer. And therefore, it is subject to Rule #1.

That may not make sense. After all, it's supposed to allow shared ownership. That must mean that this is allowable, right?

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1.get();

Nope. This is still wrong. The difference between auto_ptr and shared_ptr is that you can do this with shared_ptr:

shared_ptr<int> p1 = new int(4);
shared_ptr<int> p2 = p1;

That's copy construction of p2 from p1. There is a fundamental difference between creating a shared_ptr from a naked pointer and creating one from an already existing shared_ptr. The latter is what actually shares ownership between the two. The former will just cause badness.

Therefore, if you ever have a naked pointer and put it in a shared_ptr, you can only do this for that pointer one time. If you want to share ownership, you must copy it around.

There is one semi-backdoor: enable_shared_from_this. If you derive a class from this type, then your class will have a shared_from_this private member that member functions of the class can use to transfer ownership around. So:

struct Type : public enable_shared_from_this
{
  DoSomething()
  {
    shared_ptr<Type> p2 = shared_from_this();
    FunctionThatTakesOwnership(p2);
  }
};

shared_ptr<Type> p1 = new Type;
p1->DoSomething();

Other than that, you'll have to transfer ownership by explicitly copying the object around.

森罗 2024-12-12 01:28:39

shared_ptr,顾名思义,如果从不同的地方引用了shared_ptr指向的对象,则应该使用shared_ptr。

例如 - 类 A1 和 A2 应该使用相同的 S 类型对象。因此两者都应该持有指向 S 的指针。但是谁独占它(谁应该删除它)。就说A1吧。因此,A1 在其析构函数中将删除 S。但是,如果 A1 在 A2 之前被销毁,会发生什么情况 - A2 将具有指向 S 的悬空指针(指向已删除对象的指针)。使用共享指针而不是指向 S 的原始指针 (S*) 可以解决此问题。

shared_ptr, as its name states, should be used if an object, pointed by shared_ptr, is referenced from different places.

For example - class A1 and A2 should use same object of type S. So both should hold pointer to S. But who exclusively owns its (who should delete it). Let's say A1. So, A1 in its destructor will delete S. But what happen if A1 is destroyed before A2 - A2 will have dangling pointer (pointer to deleted object) to S. Using shared_ptr instead of raw pointer to S (S*) solves this problem.

醉殇 2024-12-12 01:28:39

共享指针取得所指向对象的所有权

其语义是,当复制shared_ptr时,每个人依次共享一个句柄,以获取其共享的所有权知识。当最后一个副本被销毁时,它就销毁了该对象。这使您不必在正确的时间手动管理对 delete 的调用,并且(希望)使内存泄漏更少。

为了做到这一点,正常的风格是在创建shared_ptr时为其提供一个new堆对象,并避免此后直接使用原始指针。

您在STL集中使用shared_ptr是正确的。这是确保集合被销毁时对象被清理的正确方法。

The shared pointer takes ownership of the object pointed to.

The semantics of this is that when the shared_ptr is copied, each in turns shares a handle to their shared knowledge of the ownership. When the last copy is destroyed, it destroys the object. This saves you from having to manually manage the call to delete at the right time, and (hopefully) make memory leaks rarer.

To make this work, the normal style is to give a new heap object to a shared_ptr when it is created, and avoid thereafter directly working with the raw pointer.

You are correct in using shared_ptr within the STL set. This is the right way to ensure that the object is cleaned up when the set is destroyed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文