【问题标题】:Why is my unique_ptr immediately deleting itself?为什么我的 unique_ptr 会立即自行删除?
【发布时间】:2021-04-22 21:55:05
【问题描述】:

我正在玩一些我仍然很陌生的概念。我想做的是使用唯一指针将“屏幕”对象依赖注入私有成员“TempCtrl::mScreen”。我相信我正确地实现了设计模式,但我从来没有用唯一的指针做到这一点,而且似乎指针在 TempCtrl 构造函数调用之前被删除了。为什么会这样?

主要功能摘录:

#include "tempctrl.hpp"
#include "screen.hpp"
#include <memory>
 
int main()
{
  std::unique_ptr<Screen> _Screen(new Screen);
  TempCtrl tc(_Screen);
 
  /* ... */ 
}

TempCtrl 构造函数声明摘录:

class TempCtrl
{
  public:
  TempCtrl(std::unique_ptr<Screen> _Screen);
 
  ~TempCtrl();

  private:
  std::unique_ptr<Screen> mScreen;
};

TempCtrl 实现摘录:

TempCtrl::TempCtrl(std::unique_ptr<Screen> _Screen)
: mScreen(_Screen)
{

}

编译器输出:

/usr/bin/g++ -std=c++11 -g -c screen.cpp tempctrl.cpp main.cpp
tempctrl.cpp: In constructor 'TempCtrl::TempCtrl(std::unique_ptr<Screen>)':
tempctrl.cpp:6:18: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Screen; _Dp = std::default_delete<Screen>]'
 : mScreen(_Screen)
                  ^
In file included from /usr/include/c++/8/memory:80,
                 from tempctrl.hpp:14,
                 from tempctrl.cpp:1:
/usr/include/c++/8/bits/unique_ptr.h:394:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
main.cpp: In function 'int main()':
main.cpp:9:22: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Screen; _Dp = std::default_delete<Screen>]'
   TempCtrl tc(_Screen);
                      ^
In file included from /usr/include/c++/8/memory:80,
                 from tempctrl.hpp:14,
                 from main.cpp:1:
/usr/include/c++/8/bits/unique_ptr.h:394:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
In file included from main.cpp:1:
tempctrl.hpp:68:3: note:   initializing argument 1 of 'TempCtrl::TempCtrl(std::unique_ptr<Screen>)'
   TempCtrl(std::unique_ptr<Screen> _Screen);
   ^~~~~~~~
make: *** [Makefile:14: *.o] Error 1

【问题讨论】:

    标签: c++ c++11 dependency-injection unique-ptr


    【解决方案1】:

    使用删除的函数并不意味着某些东西正在删除自己。

    在 C++ 中删除的函数是一个函数,当 C++ 编译器认为它应该调用它时,它会故意生成错误。

    在这里,您删除的函数是您的unique_ptr 的“复制构造函数”。

    复制构造函数是在 C++ 中获取对象并制作另一个副本的方式。

    unique_ptr 应该是唯一的。复制独特的东西是违反规则的。

    您尝试调用该构造函数...尝试复制 unique_ptr

    std::unique_ptr<Screen> _Screen(new Screen);
    TempCtrl tc(_Screen); // <— here
    

    这里有唯一指针_Screen1。它唯一且仅拥有new Screen 资源。

    然后您创建一个TempCtrlTempCtrl tc 的构造函数接受 unique_ptr&lt;Screen&gt; 的值——这是另一个唯一指针。

    因此,当您调用该构造函数时,C++ 编译器会尝试复制 unique_ptr,并向您发出错误,表示“不允许您这样做”。

    您必须将您的unique_ptr&lt;Screen&gt; 移动(转让所有权)到TempCtrl

    TempCtrl tc(std::move(_Screen));
    

    或者,您必须通过引用传递unique_ptr

    TempCtrl(std::unique_ptr<Screen> const & _screen);
    

    或者,只传递原始指针:

    TempCtrl(Screen* _screen);
    

    这些反过来又需要更改其他代码才能使其正常工作。在控件内存储指向屏幕的唯一指针意味着该控件而不是其他控件拥有该屏幕。这看起来很奇怪。

    unique_ptr 表示只有一个智能指针在指向对象的生命周期内拥有唯一且完整的所有权。因此,具有相同对象的两个唯一指针是无稽之谈。


    您似乎已经习惯了垃圾收集语言。在 C++ 中,您对与之交互的每个对象的生命周期负责。智能指针可以帮助解决这个问题,但在 C++ 中没有智能指针 可以让您不关心对象的生命周期(盲目且不加思索地,为此目的使用共享指针只会使对象生命周期变得不可见更难找到错误)。

    这会给你带来额外的认知负担,这是你不习惯思考的事情。 C++ 中有一些技术可以减少这种负载,但学习它们并非易事。

    这可能是shared_ptrweak_ptr 正确的情况之一,但我不确定。只要任何控件保持活动状态,屏幕就保持活动状态是奇怪的,而一个控件比它所在的屏幕持续时间更长也是奇怪的。

    我怀疑控件应该存在于布局中,并且只有在绘制时它们才会从布局中获取屏幕。布局将管理控件的生命周期。并且绘图功能将存在于布局之外,并通过屏幕调用布局。

    思考哪些代码应该负责、拥有和管理哪些其他代码在工作。祝你好运。


    1 顺便说一下,_Screen 这个名字是由 C++ 实现保留的;你使用它是非法的。不要以_ 后跟大写字母开头标识符,这会使您的程序格式错误,但不需要诊断)。人们复制系统头文件,这些头文件被允许使用,因为它们是由编译器供应商编写的,并以这种方式制作格式错误的程序。

    【讨论】:

    • 谢谢,我修改了命名方案并从 main 中完全删除了“LcdScreen”功能,只使用了 TempCtrl 初始化列表来调用 LcdScreen 类。我采用这种方法的原因是我正在尝试创建一个线程和原子安全的类来写入 LCD 屏幕中的各个点。因为这是这个类的唯一目的,所以将它与任何不会使用它的东西分离似乎是有意义的。
    猜你喜欢
    • 1970-01-01
    • 2014-03-23
    • 2017-03-03
    • 1970-01-01
    • 2016-07-13
    • 2011-10-31
    相关资源
    最近更新 更多