首页 > 解决方案 > 为什么我的 unique_ptr 会立即自行删除?

问题描述

我正在玩一些我仍然很陌生的概念。我想做的是使用唯一指针将“屏幕”对象依赖注入私有成员“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++11dependency-injectionunique-ptr

解决方案


使用已删除的功能并不意味着某些东西正在删除自己。

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

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

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

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

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

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

在这里,您有唯一的指针_Screen1。它是唯一的并且仅拥有该new Screen资源。

然后创建一个TempCtrl. 的构造函数TempCtrl 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++ 中有一些技术可以减少这种负载,但学习它们并非易事。

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

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

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


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


推荐阅读