Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 删除“后阻止对象使用”;这";指针_C++_Qt_Pointers_Qml_Object Lifetime - Fatal编程技术网

C++ 删除“后阻止对象使用”;这";指针

C++ 删除“后阻止对象使用”;这";指针,c++,qt,pointers,qml,object-lifetime,C++,Qt,Pointers,Qml,Object Lifetime,我正在开发一个有以下问题的应用程序。基本上,有很多对象可能会隐式地破坏它们自己 void Foo::func() { ... Bar b; b.func2(); } 这里的func2可能会破坏调用它的foo对象。由于这种情况不太明显,我想确保在调用后不能访问foo对象的成员变量,因为我不能保证它们仍然有效。如果这次对b的调用是最后一次调用,我很好,但是因为我不是唯一一个参与这个项目的人,而且破坏也不明显,我想在这些调用之后实现一些东西来阻止使用这个。有没有一种方法可以在

我正在开发一个有以下问题的应用程序。基本上,有很多对象可能会隐式地破坏它们自己

void Foo::func()
{
    ...
    Bar b;
    b.func2();
}
这里的
func2
可能会破坏调用它的
foo
对象。由于这种情况不太明显,我想确保在调用后不能访问
foo
对象的成员变量,因为我不能保证它们仍然有效。如果这次对b的调用是最后一次调用,我很好,但是因为我不是唯一一个参与这个项目的人,而且破坏也不明显,我想在这些调用之后实现一些东西来阻止使用
这个
。有没有一种方法可以在不完全重构当前设计的情况下实现这一点(因为它在项目中被广泛使用)

一些背景信息:

是QTUI应用程序,使用QML跟踪一组“屏幕”(屏幕是QML+相应的C++模型)。在我的示例中,

Bar
类是控制屏幕寿命的“堆栈管理器”。这是一个单身汉(我知道)。<代码> Foo> /Cord>类是一个特定的QML的C++模型。函数
Foo::func()
是一个可以从QML中的用户输入或其他系统事件调用的函数。该函数通常会处理事件,但有时它会告诉屏幕管理器删除一个或多个屏幕,然后删除与该屏幕对应的模型(可能是调用模型)

严重的设计问题? 无法阻止
指针。与所有原始指针一样,在取消引用它之前,必须确保它是有效的

但这还不是全部:如果调用
fun2()
Foo
是自动存储持续时间的本地对象,该怎么办

  • 如果要通过调用其析构函数来销毁函数调用中的对象,则必须确保在同一位置仍然存在有效的对象:否则,在离开定义对象的块时自动调用析构函数可能会导致未定义的行为
  • 如果您删除对象而不是仅仅销毁它,那么它将是未定义的
具有智能指针的替代设计 解决这种情况的一种方法是使用创建所有
Foo
Bar
对象(确保构造函数不是公共的),并让这些工厂返回
shared\u ptr

这样做的好处是,如果一个对象不再被使用,它将自毁。这比手动管理销毁要干净得多

然而,您将面临几个挑战:

  • 您必须重构所有代码,以智能指针替换原始指针
  • 为了避免由于交叉引用(两个对象各自保持一个slart指针指向另一个对象)而导致无休止的活动,您需要确定何时使用
    共享\u ptr
    (如果指针必须确保对象仍处于活动状态)以及何时使用
    弱\u ptr
    (即,不利于保持对象活动的指针)
具有状态的替代设计 另一种选择是使用状态来区分可以使用的活动对象和不再使用的已死亡对象。因此,您可以调用一个状态更改函数来清理/重置对象,而不是删除对象

这可以通过以下方式实现:

  • 或者非常好地使用了(但这可能需要一些广泛的重构)
  • 或者使用简单的标志。然后,在每个成员函数开始时,以及在访问可能更改对象状态的调用之后的数据成员之前,都会对其进行检查。这仍然是容易出错的,需要进行分析,但主要需要“本地”更改,从而为重构提供了更大的灵活性
这种方法的优点是状态更改函数非常简单(目前析构函数中的大部分内容,但避免它们可能会在第二次意外完成),并且使棘手的部分非常明显


困难在于要确保死者的物品被彻底清理干净。因此,您需要解决前面已经提到的所有权问题,并确保对象在其行为中间没有被删除。

也许会引入所有权的概念,尤其是共享所有权。可能在的帮助下。除非您添加一层“伪破坏性”
,否则此
在破坏后将处于无效状态,您不能依赖它。这对你的问题是一个“不”。从问题中提供的信息很难判断哪种设计最能满足您对尽可能少的重构和尽可能多的安全性的需求。简单的回答是
b.func2()
不应该破坏
b
,因为这是一个可怕的设计决策。在您的用例中,这样做会导致调用方
Foo::func()
具有未定义的行为,因为它可能会第二次破坏
b
(当它超出范围时)。相反,返回一个值,该值指示调用者应停止使用
b
,并允许其生命终止(例如,在您的示例中通过返回)。@Peter
b.func2()
将根据问题销毁
foo
(类型为
foo
),不是
b
@Frank问题中缺少的一条关键信息是
b.func2
如何知道调用它的
foo
。如前所述,必须存在一些全局状态,否则
b
不知道存在哪些或有多少
Foo
对象(如果从a
Foo
外部调用
b.func2()
,会发生什么情况)。