【问题标题】:Are there real use cases for smart pointers?智能指针有真正的用例吗?
【发布时间】:2021-02-23 06:33:17
【问题描述】:

我正在阅读 C++ 中的智能指针,令我惊讶的是,超过 99% 的给定示例实际上是相当糟糕的示例,因为在这些情况下可以避免动态分配。我同意仅在 STL 容器不起作用的情况下使用智能指针。例如,在动态数组 (std::vector) 中,性能很重要,因此最好使用经过良好测试的代码而不使用任何智能指针。

这是我认为不好的例子,因为在这种情况下unique_ptr 不是解决方案,但堆栈分配是正确的方法。

MyObject* ptr = new MyObject(); 
ptr->DoSomething(); 
delete ptr; 

那么 C++ 中的智能指针有哪些好的示例或用途?

换句话说,将指针的所有权转移到另一个对象需要什么设计模式?

【问题讨论】:

  • 这个问题听起来像是在咆哮,我真的不明白你在问什么
  • "如果对象从向量中移除,那么它将被删除" 否。我建议你在抱怨高级之前先学习基础......
  • 动态内存分配是开销。在这种情况下使用智能指针不会增加开销。无意冒犯,但您似乎有一些误解
  • 如果您不使用智能指针,您需要一些其他方法来跟踪对象的生命周期。这是有代价的,而且容易出错。智能指针已被证明是解决常见问题的好方法
  • unique_ptr 没有超过 new 的开销,并且是默认的智能指针

标签: c++ pointers smart-pointers


【解决方案1】:

令我惊讶的是,超过 99% 的给定示例实际上是相当糟糕的示例,因为在这些情况下可以避免动态分配

这可能是因为这些示例旨在超级简单。

那么,什么是 C++ 中智能指针的好例子或用途?

不要介意“善良”,但请考虑以下相关案例示例:

1。当你抓不住栈时

template <typename T>
std::unique_ptr<T[]> print_and_allocate(std::size_t n)
{
    std::cout << "Allocating " << n << " elements of size " << sizeof(T) << '\n';
    return std::make_unique<T[]>(n);
}

您无法在堆栈上执行分配,因为您在使用分配的元素之前返回。此外,您不能只返回单个构造的或 std::array,因为事先不知道要分配的元素数量。

2。需要引用几个可能的子类之一

class A;
class B : public A { /* ... */ };
class C : public A { /* ... */ };

// ...

auto my_a = std::unique_ptr<A>(condition ? (A*) new B : (A*) new C);
my_a.some_virtual_method();

3。复杂的解除分配逻辑

指针不会告诉您何时/如何释放/释放它。你可以做一个简单的假设(“我需要释放我从这个函数中得到的指针”),但这已经表明你在包装类中表达你的假设。如果取消分配的条件更复杂,尤其是如果指针接收者不知道它们,那么以某种方式传达它们就变得至关重要。 std::shared_ptrstd::weak_ptr 是这样做的两种方法;另一个是std::unique_ptrcustom deleter

4。当无法保证未来的可用性时

当指针的提供者不能保证它会继续有效,但预计它可能会是 - 你需要某种包装类来反映这一事实并确保你不会尝试取消引用当你实际上不能的时候指针。这就是std::weak_ptr() 发挥作用的地方。


更一般地说:如果您之前需要分配内存并持有一个指针,出于某种原因,并且没有它就无法做到 - 您很可能希望改用智能指针。另见:

What is a smart pointer and when should I use one (answer).

【讨论】:

  • 在您的示例中,您可以返回一个std::vector,它将被自动删除。不需要unique_ptr。我错了吗?
  • @nowox:不,你没有错。但请考虑我的一般观点:如果您想要的是 std::vector,那么您一开始就不会使用指针。
  • @nowox 如果您的类不可复制且不可移动,则不能将其放入向量中。此外,由于 unique_ptr 不具备 vector 的所有功能,因此如果您不需要 vector 的功能,它的开销可能会更少。
【解决方案2】:

那么,什么是 C++ 中智能指针的好例子或用途?

需要在堆上拥有资源的任何情况。

您说得对,大多数智能指针示例都是在现实世界场景中使用堆栈分配编写的。但它们只是 - 展示智能指针的使用/优势的简单示例。

然而,实际上,您不能将所有内容都放在堆栈上。一旦你需要在堆上动态分配内存,智能指针几乎总是比带有 new/delete 的原始指针更好的选择。

【讨论】:

  • “你是对的,大多数智能指针示例......”这已经在零证据的问题中提到过,重复它仍然不能说服我,只是说
  • @idclev463035818 说服你做什么?很多教科书/教程代码 sn-ps 没有在现实世界场景中显示代码,而是使用了一个最小的示例?例如,只需获取有关智能指针的 cppreference 条目:Link。这就是op所说的。实际上,您永远不会对 my_func() 内部的本地 int 使用指针,无论是否智能。它在这里只是用来演示如何使用智能指针来帮助避免内存泄漏。
  • 我的意思是 OP 写的是“99%”,你写的是“大部分”,我看不到。我刚刚检查了我在网上找到的前 7 个智能指针示例。从某种意义上说,它们中的 2 个很差,因为它们使用的场景是您一开始就不会使用动态分配。 7 个中有 2 个既不是“大多数”也不是 99%。 7当然是太少的统计数据,无法做出一般性陈述,但它比没有更重要。对不起,我有时有点挑剔。我只是不认为这是大多数例子
  • 那个 cppref 网站上的第一个例子是 btw 很差,我同意 ;)
【解决方案3】:

在实际用例中,您实际上并不想关心内存管理。您不希望内存泄漏,因为您在某处忘记了delete。这就是智能指针派上用场的地方,因为它们解除了您清理的责任。

【讨论】:

  • 如果我不想关心内存管理,我可能会使用高级语言,而不是 C++。当我使用 C/C++ 时,这是因为我有硬限制,例如有限的内存或有限的 CPU 时间。
  • @nowox 使用手动 new/delete 对内存限制或 CPU 时间没有帮助。 unique_ptr 实际上是一个零成本的抽象。
  • 我部分同意unique_ptr,因为你仍然有一个间接的成本。在大多数用例中它是值得的,但在某些嵌入式实时目标上可能是一个问题。
猜你喜欢
  • 2013-04-16
  • 2018-07-17
  • 1970-01-01
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 2014-09-25
  • 1970-01-01
  • 2012-07-02
相关资源
最近更新 更多