在visual studio中,您可以在已删除的对象上调用函数:
class Foo {
void bar() {
...
}
};
您实际上可以执行以下代码而不会出错:
Foo * foo = new Foo();
delete foo;
foo->bar();
并且只要Foo :: bar中的代码不对this
指针执行任何操作。我的第一个问题是,这种未定义的行为是否正常工作或是否符合标准?
第二个问题:
如果我们将代码更改为:
Foo * foo = new Foo();
delete foo;
foo = nullptr;
foo->bar();
我们可以在Foo :: bar中使用以下检查
if (this == nullptr) {
...
}
以确定我们是否对有效对象进行操作。虽然这样做似乎不太好主意,但是有没有任何架构/设计可能有用呢?
答案 0 :(得分:6)
两种用途都只是简单的UB。
编译器甚至可以优化 if (this == nullptr)
,因为合法代码中的this
永远不会nullptr
。 Clang警告说这个顺便说一句。
更新:从gcc 6开始,gcc实际上会根据假设this != nullptr
进行优化。他们还添加了警告。见live。
答案 1 :(得分:3)
如果方法不执行任何类成员,则它应该是static
。可以始终在没有任何对象的情况下调用静态方法,如果不是这样,编译器会给出错误。
支票
if ( this )
对我来说非常肮脏。仅出于测试目的,assert
听起来很有帮助。但是如果我必须担心一个方法可以在没有对象的情况下调用,那么就没有机会得到指针(this)设置为nullptr
有效的保存。这是错误转移而不是解决方案。
如果方法是virtual
,那么对this==nullptr
的检查就会迟到,因为无法找到vtable ptr。
程序的设计应该以适当的方式处理新的/删除。也许使用任何类型的智能指针都可以提供帮助。
答案 2 :(得分:2)
foo->bar()
始终取消引用foo
。
删除指针后取消引用指针会产生未定义的行为。如果Visual Studio碰巧没有出错,那就是偶然。任何结果都是允许未定义的行为,包括没有明显的错误。
将foo
设置为nullptr
,然后调用foo->bar()
也会产生未定义的行为,因为它取消引用了NULL指针。在this == nullptr
内测试Foo::bar()
并不会改变这一点,因为调用者甚至在调用Foo::bar()
之前就已经表现出未定义的行为。
答案 3 :(得分:0)
<Window x:Class="ProtocolAnalyzer.createByProtocol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="createByProtocol" Height="506" Width="384">
<Grid Margin="0,0,2,4">
<DataGrid x:Name="dataGridTable" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="452" Width="245" SelectedCellsChanged="dataGridTable_SelectedCellsChanged" >
<DataGrid.Columns>
</DataGrid.Columns>
</DataGrid>
<Button Content="Create" HorizontalAlignment="Left" Margin="275,165,0,0" VerticalAlignment="Top" Width="75" Height="75" Click="Button_Click"/>
</Grid>
</Window>
此语句表示解码foo中的地址。并将其放入调用堆栈,然后将bar的变量内容放入调用堆栈。最后,执行该功能。
如果:: bar()函数完全为空。没关系。
否则,即使您只是声明一些变量。你的函数调用已经弄脏了* foo的地址。
1)如果foo == nullptr。 0x0000000是一个只读部分,你的程序会崩溃,或者当你的main结束时抛出异常。
2)如果foo!= nullptr,但它被删除了。堆将损坏,内存屏障可能会检测到您的操作,它可能会崩溃
3)如果foo!= nullptr,那就是堆栈变量。堆栈很脏,会崩溃。