指针,智能指针还是共享指针?(复制)

时间:2023-01-05 21:17:44

This question already has an answer here:

这个问题已经有了答案:

I am programming with normal pointers, but I have heard about libraries like Boost that implement smart pointers. I have also seen that in Ogre3D rendering engine there is a deep use of shared pointers.

我正在用普通指针编程,但我听说过Boost之类的库实现智能指针。我还看到,在Ogre3D渲染引擎中,共享指针的使用非常广泛。

What exactly is the difference between the three, and should I stick on using just a type of them?

这三者之间的区别到底是什么?我是否应该继续使用它们?

5 个解决方案

#1


136  

Sydius outlined the types fairly well:

西迪厄斯很好地概括了这些类型:

  • Normal pointers are just that - they point to some thing in memory somewhere. Who owns it? Only the comments will let you know. Who frees it? Hopefully the owner at some point.
  • 普通指针只是指向内存中的某个地方。谁拥有它?只有评论才会让你知道。谁使它?希望老板在某个时候。
  • Smart pointers are a blanket term that cover many types; I'll assume you meant scoped pointer which uses the RAII pattern. It is a stack-allocated object that wraps a pointer; when it goes out of scope, it calls delete on the pointer it wraps. It "owns" the contained pointer in that it is in charge of deleteing it at some point. They allow you to get a raw reference to the pointer they wrap for passing to other methods, as well as releasing the pointer, allowing someone else to own it. Copying them does not make sense.
  • 智能指针是一个涵盖多种类型的通用术语;我假设您指的是使用RAII模式的作用域指针。它是包装指针的堆栈分配对象;当它超出范围时,它调用它所包装的指针上的delete。它“拥有”包含的指针,因为它负责在某个点删除它。它们允许您获得对传递给其他方法的指针的原始引用,以及释放指针,允许其他人拥有它。复制它们是没有意义的。
  • Shared pointers is a stack-allocated object that wraps a pointer so that you don't have to know who owns it. When the last shared pointer for an object in memory is destructed, the wrapped pointer will also be deleted.
  • 共享指针是一个堆栈分配的对象,它封装一个指针,这样您就不必知道谁拥有它。当内存中对象的最后一个共享指针被销毁时,包装的指针也将被删除。

How about when you should use them? You will either make heavy use of scoped pointers or shared pointers. How many threads are running in your application? If the answer is "potentially a lot", shared pointers can turn out to be a performance bottleneck if used everywhere. The reason being that creating/copying/destructing a shared pointer needs to be an atomic operation, and this can hinder performance if you have many threads running. However, it won't always be the case - only testing will tell you for sure.

你应该什么时候使用它们呢?您将大量使用范围指针或共享指针。在您的应用程序中运行了多少线程?如果答案是“潜在的很多”,那么共享指针在任何地方都可能成为性能瓶颈。原因是,创建/复制/销毁共享指针需要是一个原子操作,如果您有许多线程正在运行,这可能会妨碍性能。然而,情况并非总是如此——只有测试才能肯定地告诉您。

There is an argument (that I like) against shared pointers - by using them, you are allowing programmers to ignore who owns a pointer. This can lead to tricky situations with circular references (Java will detect these, but shared pointers cannot) or general programmer laziness in a large code base.

有一个参数(我喜欢)反对共享指针——通过使用它们,程序员可以忽略谁拥有指针。这可能导致循环引用的复杂情况(Java将检测到这些,但共享指针不能),或者程序员在大型代码库中普遍存在的惰性。

There are two reasons to use scoped pointers. The first is for simple exception safety and cleanup operations - if you want to guarantee that an object is cleaned up no matter what in the face of exceptions, and you don't want to stack allocate that object, put it in a scoped pointer. If the operation is a success, you can feel free to transfer it over to a shared pointer, but in the meantime save the overhead with a scoped pointer.

使用作用域指针有两个原因。第一个是用于简单的异常安全和清理操作——如果您想要保证一个对象在任何情况下都被清理,并且您不希望对该对象进行堆栈分配,那么请将它放在一个作用域指针中。如果操作成功,您可以将其转移到共享指针,但同时使用作用域指针保存开销。

The other case is when you want clear object ownership. Some teams prefer this, some do not. For instance, a data structure may return pointers to internal objects. Under a scoped pointer, it would return a raw pointer or reference that should be treated as a weak reference - it is an error to access that pointer after the data structure that owns it is destructed, and it is an error to delete it. Under a shared pointer, the owning object can't destruct the internal data it returned if someone still holds a handle on it - this could leave resources open for much longer than necessary, or much worse depending on the code.

另一种情况是你想要清晰的对象所有权。有些团队喜欢这样,有些则不喜欢。例如,数据结构可以返回指向内部对象的指针。在作用域指针下,它将返回一个原始指针或引用,应该将其视为弱引用——在拥有该指针的数据结构被销毁后访问该指针是错误的,删除该指针是错误的。在共享指针下,如果有人仍然持有它的句柄,所有者对象不能破坏它返回的内部数据——这可能会使资源开放的时间比必要的时间长得多,或者更糟糕,这取决于代码。

#2


31  

the term "smart pointer" includes shared pointers, auto pointers, locking pointers and others. you meant to say auto pointer (more ambiguously known as "owning pointer"), not smart pointer.

术语“智能指针”包括共享指针、自动指针、锁定指针和其他。您的意思是说自动指针(更模糊地称为“拥有指针”),而不是智能指针。

Dumb pointers (T*) are never the best solution. They make you do explicit memory management, which is verbose, error prone, and sometimes nigh impossible. But more importantly, they don't signal your intent.

哑指针(T*)从来都不是最好的解决方案。它们使您执行显式内存管理,这是冗长的、容易出错的,有时几乎是不可能的。但更重要的是,它们并不表明你的意图。

Auto pointers delete the pointee at destruction. For arrays, prefer encapsulations like vector and deque. For other objects, there's very rarely a need to store them on the heap - just use locals and object composition. Still the need for auto pointers arises with functions that return heap pointers -- such as factories and polymorphic returns.

自动指针在销毁时删除指针。对于数组,更喜欢像vector和deque这样的封装。对于其他对象,很少需要将它们存储在堆中——只需使用局部变量和对象组合。仍然需要自动指针,因为函数返回堆指针——比如工厂和多态返回。

Shared pointers delete the pointee when the last shared pointer to it is destroyed. This is useful when you want a no-brainer, open-ended storage scheme where expected lifetime and ownership can vary widely depending on the situation. Due to the need to keep an (atomic) counter, they're a bit slower than auto pointers. Some say half in jest that shared pointers are for people who can't design systems -- judge for yourself.

当指向共享指针的最后一个共享指针被销毁时,共享指针将删除该指针。当您想要一个无需动脑筋的、开放式的存储方案时,这是非常有用的,在这个方案中,预期的生命周期和所有权可以根据情况的不同而有很大的差异。由于需要保持(原子)计数器,它们比自动指针慢一些。有人说,在jest中有一半的人说,共享指针是为那些不能设计系统的人提供的。

For an essential counterpart to shared pointers, look up weak pointers too.

对于共享指针的基本对应,也要查找弱指针。

#3


20  

Smart pointers will clean themselves up after they go out of scope (thereby removing fear of most memory leaks). Shared pointers are smart pointers that keep a count of how many instances of the pointer exist, and only clean up the memory when the count reaches zero. In general, only use shared pointers (but be sure to use the correct kind--there is a different one for arrays). They have a lot to do with RAII.

智能指针在超出范围后会自动清理(从而消除了对大多数内存泄漏的恐惧)。共享指针是一种智能指针,它记录有多少实例存在,并且只在计数为0时清理内存。通常,只使用共享指针(但一定要使用正确的指针类型——数组有不同的指针)。他们和雷有很大关系。

#4


8  

To avoid memory leaks you may use smart pointers whenever you can. There are basically 2 different types of smart pointers in C++

为了避免内存泄漏,你可以随时使用智能指针。在c++中基本上有两种不同类型的智能指针

  • Reference counted (e.g. boost::shared_ptr / std::tr1:shared_ptr)
  • 引用计数(例如boost: shared_ptr / std::tr1:shared_ptr)
  • non reference counted (e.g. boost::scoped_ptr / std::auto_ptr)
  • 非引用计数(例如boost: scoped_ptr / std::auto_ptr)

The main difference is that reference counted smart pointers can be copied (and used in std:: containers) while scoped_ptr cannot. Non reference counted pointers have almost no overhead or no overhead at all. Reference counting always introduces some kind of overhead.

主要的区别是,可以复制引用计数的智能指针(并在std:: container中使用),而scoped_ptr不能。非引用计数指针几乎没有开销或根本没有开销。引用计数总是会引入一些开销。

(I suggest to avoid auto_ptr, it has some serious flaws if used incorrectly)

(我建议避免auto_ptr,如果使用不当会有一些严重的缺陷)

#5


5  

To add a small bit to Sydius' answer, smart pointers will often provide a more stable solution by catching many easy to make errors. Raw pointers will have some perfromance advantages and can be more flexible in certain circumstances. You may also be forced to use raw pointers when linking into certain 3rd party libraries.

要为Sydius的答案添加一点内容,智能指针通常会通过捕获许多容易出错的错误来提供更稳定的解决方案。原始指针将有一些额外的优势,并且在某些情况下可以更加灵活。在链接到某些第三方库时,您可能还*使用原始指针。

#1


136  

Sydius outlined the types fairly well:

西迪厄斯很好地概括了这些类型:

  • Normal pointers are just that - they point to some thing in memory somewhere. Who owns it? Only the comments will let you know. Who frees it? Hopefully the owner at some point.
  • 普通指针只是指向内存中的某个地方。谁拥有它?只有评论才会让你知道。谁使它?希望老板在某个时候。
  • Smart pointers are a blanket term that cover many types; I'll assume you meant scoped pointer which uses the RAII pattern. It is a stack-allocated object that wraps a pointer; when it goes out of scope, it calls delete on the pointer it wraps. It "owns" the contained pointer in that it is in charge of deleteing it at some point. They allow you to get a raw reference to the pointer they wrap for passing to other methods, as well as releasing the pointer, allowing someone else to own it. Copying them does not make sense.
  • 智能指针是一个涵盖多种类型的通用术语;我假设您指的是使用RAII模式的作用域指针。它是包装指针的堆栈分配对象;当它超出范围时,它调用它所包装的指针上的delete。它“拥有”包含的指针,因为它负责在某个点删除它。它们允许您获得对传递给其他方法的指针的原始引用,以及释放指针,允许其他人拥有它。复制它们是没有意义的。
  • Shared pointers is a stack-allocated object that wraps a pointer so that you don't have to know who owns it. When the last shared pointer for an object in memory is destructed, the wrapped pointer will also be deleted.
  • 共享指针是一个堆栈分配的对象,它封装一个指针,这样您就不必知道谁拥有它。当内存中对象的最后一个共享指针被销毁时,包装的指针也将被删除。

How about when you should use them? You will either make heavy use of scoped pointers or shared pointers. How many threads are running in your application? If the answer is "potentially a lot", shared pointers can turn out to be a performance bottleneck if used everywhere. The reason being that creating/copying/destructing a shared pointer needs to be an atomic operation, and this can hinder performance if you have many threads running. However, it won't always be the case - only testing will tell you for sure.

你应该什么时候使用它们呢?您将大量使用范围指针或共享指针。在您的应用程序中运行了多少线程?如果答案是“潜在的很多”,那么共享指针在任何地方都可能成为性能瓶颈。原因是,创建/复制/销毁共享指针需要是一个原子操作,如果您有许多线程正在运行,这可能会妨碍性能。然而,情况并非总是如此——只有测试才能肯定地告诉您。

There is an argument (that I like) against shared pointers - by using them, you are allowing programmers to ignore who owns a pointer. This can lead to tricky situations with circular references (Java will detect these, but shared pointers cannot) or general programmer laziness in a large code base.

有一个参数(我喜欢)反对共享指针——通过使用它们,程序员可以忽略谁拥有指针。这可能导致循环引用的复杂情况(Java将检测到这些,但共享指针不能),或者程序员在大型代码库中普遍存在的惰性。

There are two reasons to use scoped pointers. The first is for simple exception safety and cleanup operations - if you want to guarantee that an object is cleaned up no matter what in the face of exceptions, and you don't want to stack allocate that object, put it in a scoped pointer. If the operation is a success, you can feel free to transfer it over to a shared pointer, but in the meantime save the overhead with a scoped pointer.

使用作用域指针有两个原因。第一个是用于简单的异常安全和清理操作——如果您想要保证一个对象在任何情况下都被清理,并且您不希望对该对象进行堆栈分配,那么请将它放在一个作用域指针中。如果操作成功,您可以将其转移到共享指针,但同时使用作用域指针保存开销。

The other case is when you want clear object ownership. Some teams prefer this, some do not. For instance, a data structure may return pointers to internal objects. Under a scoped pointer, it would return a raw pointer or reference that should be treated as a weak reference - it is an error to access that pointer after the data structure that owns it is destructed, and it is an error to delete it. Under a shared pointer, the owning object can't destruct the internal data it returned if someone still holds a handle on it - this could leave resources open for much longer than necessary, or much worse depending on the code.

另一种情况是你想要清晰的对象所有权。有些团队喜欢这样,有些则不喜欢。例如,数据结构可以返回指向内部对象的指针。在作用域指针下,它将返回一个原始指针或引用,应该将其视为弱引用——在拥有该指针的数据结构被销毁后访问该指针是错误的,删除该指针是错误的。在共享指针下,如果有人仍然持有它的句柄,所有者对象不能破坏它返回的内部数据——这可能会使资源开放的时间比必要的时间长得多,或者更糟糕,这取决于代码。

#2


31  

the term "smart pointer" includes shared pointers, auto pointers, locking pointers and others. you meant to say auto pointer (more ambiguously known as "owning pointer"), not smart pointer.

术语“智能指针”包括共享指针、自动指针、锁定指针和其他。您的意思是说自动指针(更模糊地称为“拥有指针”),而不是智能指针。

Dumb pointers (T*) are never the best solution. They make you do explicit memory management, which is verbose, error prone, and sometimes nigh impossible. But more importantly, they don't signal your intent.

哑指针(T*)从来都不是最好的解决方案。它们使您执行显式内存管理,这是冗长的、容易出错的,有时几乎是不可能的。但更重要的是,它们并不表明你的意图。

Auto pointers delete the pointee at destruction. For arrays, prefer encapsulations like vector and deque. For other objects, there's very rarely a need to store them on the heap - just use locals and object composition. Still the need for auto pointers arises with functions that return heap pointers -- such as factories and polymorphic returns.

自动指针在销毁时删除指针。对于数组,更喜欢像vector和deque这样的封装。对于其他对象,很少需要将它们存储在堆中——只需使用局部变量和对象组合。仍然需要自动指针,因为函数返回堆指针——比如工厂和多态返回。

Shared pointers delete the pointee when the last shared pointer to it is destroyed. This is useful when you want a no-brainer, open-ended storage scheme where expected lifetime and ownership can vary widely depending on the situation. Due to the need to keep an (atomic) counter, they're a bit slower than auto pointers. Some say half in jest that shared pointers are for people who can't design systems -- judge for yourself.

当指向共享指针的最后一个共享指针被销毁时,共享指针将删除该指针。当您想要一个无需动脑筋的、开放式的存储方案时,这是非常有用的,在这个方案中,预期的生命周期和所有权可以根据情况的不同而有很大的差异。由于需要保持(原子)计数器,它们比自动指针慢一些。有人说,在jest中有一半的人说,共享指针是为那些不能设计系统的人提供的。

For an essential counterpart to shared pointers, look up weak pointers too.

对于共享指针的基本对应,也要查找弱指针。

#3


20  

Smart pointers will clean themselves up after they go out of scope (thereby removing fear of most memory leaks). Shared pointers are smart pointers that keep a count of how many instances of the pointer exist, and only clean up the memory when the count reaches zero. In general, only use shared pointers (but be sure to use the correct kind--there is a different one for arrays). They have a lot to do with RAII.

智能指针在超出范围后会自动清理(从而消除了对大多数内存泄漏的恐惧)。共享指针是一种智能指针,它记录有多少实例存在,并且只在计数为0时清理内存。通常,只使用共享指针(但一定要使用正确的指针类型——数组有不同的指针)。他们和雷有很大关系。

#4


8  

To avoid memory leaks you may use smart pointers whenever you can. There are basically 2 different types of smart pointers in C++

为了避免内存泄漏,你可以随时使用智能指针。在c++中基本上有两种不同类型的智能指针

  • Reference counted (e.g. boost::shared_ptr / std::tr1:shared_ptr)
  • 引用计数(例如boost: shared_ptr / std::tr1:shared_ptr)
  • non reference counted (e.g. boost::scoped_ptr / std::auto_ptr)
  • 非引用计数(例如boost: scoped_ptr / std::auto_ptr)

The main difference is that reference counted smart pointers can be copied (and used in std:: containers) while scoped_ptr cannot. Non reference counted pointers have almost no overhead or no overhead at all. Reference counting always introduces some kind of overhead.

主要的区别是,可以复制引用计数的智能指针(并在std:: container中使用),而scoped_ptr不能。非引用计数指针几乎没有开销或根本没有开销。引用计数总是会引入一些开销。

(I suggest to avoid auto_ptr, it has some serious flaws if used incorrectly)

(我建议避免auto_ptr,如果使用不当会有一些严重的缺陷)

#5


5  

To add a small bit to Sydius' answer, smart pointers will often provide a more stable solution by catching many easy to make errors. Raw pointers will have some perfromance advantages and can be more flexible in certain circumstances. You may also be forced to use raw pointers when linking into certain 3rd party libraries.

要为Sydius的答案添加一点内容,智能指针通常会通过捕获许多容易出错的错误来提供更稳定的解决方案。原始指针将有一些额外的优势,并且在某些情况下可以更加灵活。在链接到某些第三方库时,您可能还*使用原始指针。