微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我的 unique_ptr 会立即删除自己?

如何解决为什么我的 unique_ptr 会立即删除自己?

我正在尝试一些我仍然比较陌生的概念。我想要做的是使用唯一指针将“Screen”对象依赖注入到私有成员“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>&) [with _Tp = Screen; _Dp = std::default_delete<Screen>]'
   TempCtrl tc(_Screen);
                      ^
In file included from /usr/include/c++/8/memory:80,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++ 编译器认为它应该调用它时,它故意产生错误。

这里,您删除的函数是您的 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<Screen> 值——这是另一个唯一的指针。

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

要么您必须将 unique_ptr<Screen> 的所有权转移(转让所有权)到 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++ 实现保留的;你使用它是违法的。不要以 _ 开头,后跟大写字母,这会使您的程序格式错误,但不需要诊断)。人们复制系统标头,允许使用它,因为它们是由编译器供应商编写的,并以这种方式制作格式错误的程序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。