为什么 C++ 库和框架从不使用智能指针?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10334511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:54:28  来源:igfitidea点击:

Why do C++ libraries and frameworks never use smart pointers?

c++apipointerssmart-pointers

提问by laurent

I read in a few articles that raw pointers should almost never be used. Instead they should always be wrapped inside smart pointers, whether it's scoped or shared pointers.

我在几篇文章中读到,几乎不应该使用原始指针。相反,它们应该始终包含在智能指针中,无论是作用域指针还是共享指针。

However, I noticed that frameworks like Qt, wxWidgets and libraries like Boost never return nor expect smart pointers, as if they were not using them at all. Instead, they return or expect raw pointers. Is there any reason for that? Should I stay away from smart pointers when I write a public API, and why?

然而,我注意到像 Qt、wxWidgets 这样的框架和像 Boost 这样的库从不返回也不期待智能指针,就好像它们根本没有使用它们一样。相反,它们返回或期望原始指针。有什么理由吗?当我编写公共 API 时,我应该远离智能指针,为什么?

Just wondering why smart pointers are recommended when many major projects seem to avoid them.

只是想知道为什么在许多主要项目似乎避免使用智能指针时推荐使用它们。

采纳答案by Jon Purdy

Apart from the fact that many libraries were written before the advent of standard smart pointers, the biggest reason is probably the lack of a standard C++ Application Binary Interface (ABI).

除了许多库是在标准智能指针出现之前编写的,最大的原因可能是缺乏标准的 C++ 应用程序二进制接口 (ABI)。

If you're writing a header-only library, you can pass around smart pointers and standard containers to your heart's content. Their source is available to your library at compile time, so you rely on the stability of their interfaces alone, not of their implementations.

如果您正在编写一个只有头文件的库,您可以将智能指针和标准容器传递给您的核心内容。它们的源代码在编译时可用于您的库,因此您仅依赖于它们接口的稳定性,而不是它们的实现。

But because of the lack of standard ABI, you generally cannotpass these objects safely across module boundaries. A GCC shared_ptris probably different from an MSVC shared_ptr, which too can differ from an Intel shared_ptr. Even with the samecompiler, these classes are not guaranteed to be binary compatible between versions.

但是由于缺乏标准 ABI,您通常无法安全地跨模块边界传递这些对象。GCCshared_ptr可能与 MSVC 不同shared_ptr,后者也可能与 Intel 不同shared_ptr。即使使用相同的编译器,也不能保证这些类在版本之间是二进制兼容的。

The bottom line is that if you want to distribute a prebuiltversion of your library, you need a standard ABI on which to rely. C doesn't have one, but compiler vendors are very good about interoperability between C libraries for a given platform—there are de facto standards.

最重要的是,如果您想分发库的预构建版本,则需要一个可依赖的标准 ABI。C 没有,但编译器供应商非常擅长给定平台的 C 库之间的互操作性——有事实上的标准。

The situation is not as good for C++. Individual compilers can handle interoperation between their own binaries, so you have the option of distributing a version for every supported compiler, often GCC and MSVC. But in light of this, most libraries just export a C interface—and that means raw pointers.

对于 C++ 来说,情况就没有那么好了。各个编译器可以处理它们自己的二进制文件之间的互操作,因此您可以选择为每个受支持的编译器分发一个版本,通常是 GCC 和 MSVC。但鉴于此,大多数库只导出 C 接口——这意味着原始指针。

Non-library code should, however, generally prefer smart pointers over raw.

然而,非库代码通常应该更喜欢智能指针而不是原始代码。

回答by iammilind

There can be many reasons. To list few of them:

可能有很多原因。列出其中的几个:

  1. Smart pointers became part of standard just recently. Till then they were part of other libraries
  2. Their primary use is to avoid memory leaks; many libraries don't have their own memory management; Generally they provide utilities and APIs
  3. They are implemented as wrapper, since they are actually objects and not pointers. Which has additional time/space cost, compared to raw pointers; The users of the libraries may not want to have such overheads
  1. 智能指针最近才成为标准的一部分。直到那时他们是其他图书馆的一部分
  2. 它们的主要用途是避免内存泄漏;许多库没有自己的内存管理;通常他们提供实用程序和 API
  3. 它们被实现为包装器,因为它们实际上是对象而不是指针。与原始指针相比,它具有额外的时间/空间成本;图书馆的用户可能不希望有这样的开销

Edit: Using smart pointers is a completely developer's choice. It depends on various factors.

编辑:使用智能指针完全是开发人员的选择。这取决于各种因素。

  1. In performance critical systems, you may not want to use smart pointers which generates overhead

  2. The project which needs the backward compatibility, you may not want to use the smart pointers which has C++11 specific features

  1. 在性能关键系统中,您可能不想使用会产生开销的智能指针

  2. 需要向后兼容的项目,您可能不想使用具有 C++11 特定功能的智能指针

Edit2There is a string of several downvotes in the span of 24 hours because of below passage. I fail to understand why the answer is downvoted even though below is just an add-on suggestion and not an answer.
However, C++ always facilitates you to have the options open. :) e.g.

Edit2由于以下段落,在 24 小时内有一连串的反对票。我不明白为什么答案被否决,即使下面只是一个附加建议而不是答案。
但是,C++ 总是有助于您打开选项。:) 例如

template<typename T>
struct Pointer {
#ifdef <Cpp11>
  typedef std::unique_ptr<T> type;
#else
  typedef T* type;
#endif
};

And in your code use it as:

并在您的代码中将其用作:

Pointer<int>::type p;

For those who say that a smart pointer and a raw pointer are different, I agree with that. The code above was just an ideawhere one can write a code which is interchangeable just with a #define, this is not compulsion;

对于那些说智能指针和原始指针不同的人,我同意这一点。上面的代码只是一个想法,人们可以编写一个可以与 a 互换的代码#define,这不是强制性的

For example, T*has to be deleted explicitly but a smart pointer does not. We can have a templated Destroy()to handle that.

例如,T*必须显式删除,而智能指针则不需要。我们可以有一个模板Destroy()来处理。

template<typename T>
void Destroy (T* p)
{
  delete p;
}
template<typename T>
void Destroy (std::unique_ptr<T> p)
{
  // do nothing
}

and use it as:

并将其用作:

Destroy(p);

In the same way, for a raw pointer we can copy it directly and for smart pointer we can use special operation.

同样,对于原始指针,我们可以直接复制它,对于智能指针,我们可以使用特殊操作。

Pointer<X>::type p = new X;
Pointer<X>::type p2(Assign(p));

Where Assign()is as:

哪里Assign()是:

template<typename T>
T* Assign (T *p)
{
  return p;
}
template<typename T>
... Assign (SmartPointer<T> &p)
{
  // use move sematics or whateve appropriate
}

回答by Matthieu M.

There are two issues with smart pointers (pre C++11):

智能指针有两个问题(C++11 之前):

  • non-standards, so each library tend to reinvent its own (NIH syndrom & dependencies issues)
  • potential cost
  • 非标准,所以每个图书馆都倾向于重新发明自己的(NIH 综合症和依赖问题)
  • 潜在成本

The defaultsmart pointer, in that it is cost-free, is unique_ptr. Unfortunately it requires C++11 move semantics, which only appeared recently. All other smart pointers have a cost (shared_ptr, intrusive_ptr) or have less than ideal semantics (auto_ptr).

默认的智能指针,因为它是无成本,是unique_ptr。不幸的是,它需要最近才出现的 C++11 移动语义。所有其他智能指针都有成本 ( shared_ptr, intrusive_ptr) 或不太理想的语义 ( auto_ptr)。

With C++11 around the corner, bringing a std::unique_ptr, one would be tempted to think that it is finally over... I am not so optimistic.

随着 C++11 的到来,带来了一个std::unique_ptr,人们可能会认为它终于结束了......我并不那么乐观。

Only a few major compilers implement most of C++11, and only in their recent versions. We can expect major libraries such as QT and Boost to be willing to retain compatibility with C++03 for a while, which somewhat precludes the wide adoption of the new and shiny smart pointers.

只有少数主要编译器实现了 C++11 的大部分内容,而且仅在它们的最新版本中实现。我们可以期待 QT 和 Boost 等主要库愿意在一段时间内保持与 C++03 的兼容性,这在某种程度上排除了新的闪亮智能指针的广泛采用。

回答by Robot Mess

You shouldn't stay away from smart pointers, they have their use especially in applications where you have to pass a object around.

你不应该远离智能指针,它们有它们的用途,特别是在你必须传递对象的应用程序中。

Libraries tend to either just return a value or populate a object. They don't usually have objects that need to be used in a lot of places, so there is no need for them to use smart pointers (at least not in their interface, they may use them internally).

库往往要么只返回一个值,要么填充一个对象。它们通常没有需要在很多地方使用的对象,因此它们不需要使用智能指针(至少不是在它们的界面中,它们可能会在内部使用它们)。

I could take as example a library we have been working on, where after a few months of development I realized we only used pointers and smart pointers in a few classes (3-5% of all classes).

我可以拿我们一直在开发的一个库为例,经过几个月的开发,我意识到我们只在少数类中使用了指针和智能指针(占所有类的 3-5%)。

Passing variables by referencewas enough in most places, we used smart pointers whenever we had a object that could be null, and raw pointers when a library that we used forced us to.

在大多数情况下,通过引用传递变量就足够了,每当我们有一个可能为空的对象时,我们使用智能指针,当我们使用的库强迫我们使用时,我们使用原始指针。

Edit(I can't comment because of my reputation): passing variables by reference is very flexible: if you want the object to be readonly you can use a const reference (you can still do some nasty casts to be able to write the object) but you get the maximum of protection possible (it's the same with smart pointers). But I do agree that it's much nicer to just return the object.

编辑(由于我的声誉,我无法发表评论):通过引用传递变量非常灵活:如果您希望对象是只读的,您可以使用 const 引用(您仍然可以进行一些讨厌的转换以便能够编写对象) 但您可以获得最大程度的保护(这与智能指针相同)。但我确实同意返回对象要好得多。

回答by Puppy

Qt pointlessly re-invented many parts of the Standard library in an attempt to become Java. I believe that it does actually have its own smart pointers now, but in general, it is hardly a pinnacle of design. wxWidgets, as far as I'm aware, was designed long before usable smart pointers were written.

为了成为 Java,Qt 毫无意义地重新发明了标准库的许多部分。我相信它现在确实有自己的智能指针,但总的来说,它几乎不是设计的顶峰。wxWidgets,据我所知,早在编写可用的智能指针之前就设计好了。

As for Boost, I fully expect that they use smart pointers wherever appropriate. You might have to be more specific.

至于 Boost,我完全希望他们在适当的地方使用智能指针。你可能需要更具体。

In addition, don't forget that smart pointers exist to enforce ownership. If the API has no ownership semantics, then why use a smart pointer?

此外,不要忘记智能指针的存在是为了强制执行所有权。如果 API 没有所有权语义,那为什么要使用智能指针呢?

回答by thb

Good question. I don't know the specific articles to which you refer, but I have read similar things from time to time. My suspicion is that the writers of such articles tend to harbor a bias against C++-style programming. If the writer programs in C++ only when he must, then returns to Java or such as soon as he can, then he doesn't really share the C++ mindset.

好问题。我不知道你提到的具体文章,但我不时阅读类似的东西。我怀疑这些文章的作者倾向于对 C++ 风格的编程抱有偏见。如果作者只在必须的时候用 C++ 编程,然后尽快返回 Java 或其他,那么他并没有真正分享 C++ 的心态。

One suspects that some or most of the same writers prefer garbage-collecting memory managers. I don't, but I think differently than they do.

有人怀疑某些或大多数相同的作者更喜欢垃圾收集内存管理器。我没有,但我的想法与他们不同。

Smart pointers are great, but they have to keep reference counts. The keeping of reference counts bears costs -- often modest costs, but costs nonetheless -- at runtime. There is nothing wrong with saving these costs by using bare pointers, especially if the pointers are managed by destructors.

智能指针很棒,但它们必须保持引用计数。保持引用计数在运行时需要承担成本——通常是适度的成本,但仍然是成本。通过使用裸指针来节省这些成本并没有错,尤其是当指针由析构函数管理时。

One of the excellent things about C++ is its support for embedded-systems programming. The use of bare pointers is part of that.

C++ 的优点之一是它对嵌入式系统编程的支持。裸指针的使用是其中的一部分。

Update:A commenter has correctly observed that C++'s new unique_ptr(available since TR1) does not count references. The commenter also has a different definition of "smart pointer" than I have in mind. He may be right about the definition.

更新:评论者正确地观察到 C++ 的 new unique_ptr(自 TR1 起可用)不计算引用。评论者对“智能指针”的定义也与我心目中的不同。他的定义可能是对的。

Further update:The comment thread below is illuminating. All of it is recommended reading.

进一步更新:下面的评论线程很有启发性。全部推荐阅读。

回答by David C. Bishop

There are also other types of smart pointers. You might want a specialized smart pointer for something like network replication (one that detects if it's accessed and sends any modifications to the server or some such), keeps a history of changes, marks the fact that it was accessed so it can be investigated when you save data to disk and so on. Not sure if doing that in the pointer is the best solution but using the built in smart pointer types in libraries could result in people being locked into them and loosing the flexibility.

还有其他类型的智能指针。您可能需要一个专门的智能指针用于诸如网络复制之类的事情(一个检测它是否被访问并将任何修改发送到服务器或其他类似的东西),保留更改历史,标记它被访问的事实,以便可以在何时进行调查您将数据保存到磁盘等。不确定在指针中这样做是否是最好的解决方案,但在库中使用内置的智能指针类型可能会导致人们被锁定并失去灵活性。

People can have all kinds of different memory management requirements and solutions beyond smart pointers. I might want to manage memory myself, I could be allocating space for things in a memory pool so it's allocated in advance and not at runtime (useful for games). I might be using a garbage collected implementation of C++ (C++11 makes this possible although none exist yet). Or maybe I'm just not doing anything advanced enough to worry about bothering with them, I can know that I'm not going to forget to uninitialized objects and so on. Maybe I'm just confident in my ability to manage memory without the pointer crutch.

除了智能指针,人们可以有各种不同的内存管理需求和解决方案。我可能想自己管理内存,我可以为内存池中的东西分配空间,所以它是提前分配的,而不是在运行时(对游戏有用)。我可能正在使用 C++ 的垃圾收集实现(C++11 使这成为可能,尽管尚不存在)。或者,也许我只是没有做任何足够先进的事情来担心打扰它们,我知道我不会忘记未初始化的对象等等。也许我只是对自己在没有指针拐杖的情况下管理内存的能力充满信心。

Integration with C is another issue too.

与 C 的集成也是另一个问题。

Another issue is smart pointers are part of the STL. C++ is designed to be usable without the STL.

另一个问题是智能指针是 STL 的一部分。C++ 设计为无需 STL 即可使用。

回答by Ugly Davis

It also depends on what domain you work in. I write game engines for a living, we avoid boost like the plague, in games the overhead of boost isn't acceptable. In our core engine we ended up writing our own version of stl (Much like the ea stl).

这也取决于你在哪个领域工作。我以编写游戏引擎为生,我们像瘟疫一样避免 boost,在游戏中,boost 的开销是不可接受的。在我们的核心引擎中,我们最终编写了我们自己的 stl 版本(很像 ea stl)。

If i was to write a forms application, i might consider using smart pointers; but once memory management is second nature not having granular control over memory becomes quiet annoying.

如果我要编写一个表单应用程序,我可能会考虑使用智能指针;但是一旦内存管理成为第二天性,没有对内存的精细控制就会变得很烦人。