【问题标题】:If my class manages a resource correctly then what is the point in having smart poointers?如果我的班级正确管理资源,那么拥有智能指针有什么意义?
【发布时间】:2020-02-26 07:22:51
【问题描述】:

我是智能指针的新手,我喜欢将它们用于共享对象的安全性和强大功能...

我有一个问题:如果我的类在其构造函数和析构函数中管理资源,应用一些经验法则,如 Big 5 和 Big 3……我还应该使用智能指针吗?或者我的班级是他们的替代品。因为正如我在 C++ 入门 5 版中所读到的,智能指针可以解决原始指针面临的问题,例如内存泄漏、双重删除指针和访问悬空指针……我的班级可以避免这些问题:

class BallGame {
    public:
        using Resource = int;

        BallGame(int);
        BallGame(const BallGame&);
        BallGame(BallGame&&);
        BallGame& operator=(const BallGame&);
        BallGame& operator=(BallGame&&);
        ~BallGame();
    private:
        Resource m_res;
};
  • 考虑到我班级的成员正在做正确的工作,所以我可以避免使用智能指针吗?

  • 我想知道一些情况下我应该使用智能指针而不是在我的类中管理资源。

  • 它们真的像 C++ 入门书中那样用于“愚蠢的类”(定义构造函数但没有表现良好的析构函数的类)吗?

【问题讨论】:

  • 大部分资源都可以通过智能指针和自定义删除器来处理,避免编写自定义类来处理它们(或者是一种实现方式)。
  • 为什么在可以有 0 规则时使用 3/5 规则 :)

标签: c++ c++11 smart-pointers


【解决方案1】:

你的问题可以理解为

如果我在我使用的每个类中手动实现智能指针的内存所有权的正确语义,我可以避免使用智能指针吗?

是的,但为什么呢?当您需要动态数组时,您是否每次需要时都手动重新实现基本的std::vector 语义?我不这么认为。

这是图书馆的目的,避免每次都重新发明轮子。

【讨论】:

  • 谢谢!但是我的班级可以有一个std::vector 作为数据成员。
  • 你可以有一个std::unique_ptr<Foo>作为数据成员,我看不出有什么区别。
  • 另请注意:手动管理资源可能非常困难。这不仅仅是“确保在普通构造函数中正确设置并在析构函数中清除”,您通常还希望各种赋值运算符甚至提供基本的异常保证(如果发生异常则不会发生内存泄漏),更不用说强异常保证了,需要确保移动构造/分配使实例在析构函数的合法状态下被清空,等等。正确使用智能指针和其他托管资源通常意味着您甚至不必编写所有这些.
  • 是的。您的第一个问题不是您预期的错误。如果您有任何生存的希望,那么您已经消除了所有可以消除的已知风险并减轻了其余风险。是你没有看到的东西让你着迷。
【解决方案2】:

尚未提及的智能指针的另一个好处是,它们可以让阅读代码的人对对象的生命周期有一个不错的了解。带有原始指针的事情是(尤其是随着代码变得越来越复杂),可能很难弄清楚谁负责对对象调用 delete,而如果您有一个唯一指针,我们会立即知道删除将在指针超出范围。

【讨论】:

    【解决方案3】:

    正如您在书中所读到的那样:它们解决了原始指针面临的问题:考虑一下:

    int* ptr = new int[1024];
    // oh my God! forgot to free it then welcome to memory leak
    
    std::string* pStr = new std::string("Hello");
    delete pStr;
    
    //...
    // and at some point in the program you think it is time to free pStr which has been already freed (among hundreds of code lines) then welcome to U.B.
     std::cout << *pStr << std::endl; // pStr is a dangling pointer. U.B
    

    使用智能指针解决这个问题:

    std::unique_ptr<int> upi = std::make_unique(7);
    // use upi effectively and don't care about freeing it because it automatically will be freed for you.
    
    • 您的类不能支持的另一个原因是在许多对象之间有效地共享同一个对象。事实上,你可以通过在你的类中应用浅拷贝来实现这一点,但问题是谁将释放该资源,然后你最终在你的小类中实现 shared_ptr 的功能!

    • 每个新版本的 C++ 都带有新功能和新的强大功能,因此您应该坚持使用这些库,而不是重新发明。如果只是出于某种教育原因,那么练习是可以的。

    • 如果你仔细观察,你会发现真正的程序包含智能指针作为成员,这使你的类变得健壮。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-04
      • 2023-03-17
      • 2011-03-06
      • 2014-05-31
      • 2016-01-21
      相关资源
      最近更新 更多