在C++中,检查一个变量是否为nullptr可能导致访问冲突错误。

huangapple go评论51阅读模式
英文:

In C++, why does checking if a variable is nullptr may result in Access violation error?

问题

我主要是一名C#程序员,经常前往C++领域进行探险,有些东西我不太理解。

我有一个类,在.h文件中有一个成员变量,初始化如下:

AVFormatContext* formatContext = nullptr;

在类的析构函数中,我在某个地方检查这个对象是否为nullptr,像这样:

if (formatContext != nullptr)
    avformat_close_input(&formatContext);

遗憾的是,这个if语句会引发以下异常:

0x00007FFEA696920A中引发了无效参数异常(在avformat-60.dll中):访问位置0x0000000时出现0xC0000005:访问冲突。

为什么在C++中仅仅检查nullptr会引发这样的异常?

我的意思是,我并没有尝试使用这个对象,我只是检查地址是否为nullptr。
我甚至没有检查"有效性"(缺乏更好的词汇,所以这是我认为的"相同"对象还是地址被搞乱了)。

当我看到"访问冲突"异常时,对我来说就像有人绑架了这个对象,而现在它被替换成了土豆,但这肯定是不可能的吧?

编辑

让我这样问你,我们正在讨论现代(C++ 17)C++,请注意av_stuff主要是与FFmpeg相关的库调用。
我的下面评论中关于问题的逻辑和理解是否正确?

AVFormatContext* formatContext = nullptr; // formatContext是OK的,已初始化为nullptr
...
avformat_fill_the_context_(&formatContext) // formatcontex已经"填充",所以它不再是nullptr,而是指向有效的对象
...
av_do_somestuff(formatContext) //某个调用会搞乱指针
...
if (formatContext != nullptr)  //在这里我得到了异常,但我的对象在早些时候已经被搞乱了

我的思维是否正确,事情是否会发生得像这样?

英文:

I am primarily a C# programer with often expedtions to C++ land and some stuff I just don't comprehend.

I have a class that has some FFmpeg object as member variable in .h file initialized like this:

AVFormatContext* formatContext = nullptr;

In the destructor of the class at one point I am checking if this object is nullptr like this:

    if(formatContext != nullptr)
        avformat_close_input(&formatContext);

Sadly, the if line causes the following exception:

Invalid argumentException thrown at 0x00007FFEA696920A (avformat-60.dll) in Blabla.exe: 0xC0000005: Access violation reading location 0x0000000

Why is it possible in C++ that a mere check for nullptr causes such an exception ?

I mean I am not trying to use the object, I am just checking is the addresss a nullptr.
I am not even checking for "validity" for the lack of a better word (so is this the "same" object that I think it is or has the address been messed up).

When I see access violation exception it seems to me like someone kidnapped this object and in its place is now potatos, but surely this is not possible ?

Edit

Let me ask you this, we are talking about modern (C++ 17) C++ and note that av_stuff is mostly FFmpeg related library calls.
Is my logic and perception of the problem in the comments below correct ?

AVFormatContext* formatContext = nullptr; // formatContext is ok and initialized as nullptr
...
avformat_fill_the_context_(&formatContext) //formatcontex has been "filled", so its not nullptr anymore but points to a valid object
...
av_do_somestuff(formatContext) //Some call that MESSES UP THE POINTER
...
if(formatContext != nullptr)  //here I get the exception, but my object was messed up earlier 

Is my thought train correct, does stuff happen like this ?

答案1

得分: 4

为什么在C++中,仅仅检查nullptr就会导致这样的异常?

这不可能。检查本身不是问题所在。

我的意思是,我并没有尝试使用这个对象,我只是在检查地址是否为nullptr。

这个指针是另一个对象的成员,你没有展示出这个对象。很可能问题出在"this"(字面上的"this")这里。

当你说

我有一个类,它有一个FFmpeg对象作为成员变量

这告诉我们表达式

(formatContext != nullptr)

实际上是

(this->formatContext != nullptr)

并且从"this"加载成员变量是可能引发访问冲突的:如果"this"不是有效指针(因为你错误地将某物强制转换为指向你的类的指针,或者因为之前的未定义行为已经损坏了你的进程),或者如果"this"已经被删除,那么可能会引发访问冲突。

你的直觉是正确的,比较不太可能是问题所在(罕见的例外情况是具有指针陷阱表示的平台)- 你只是没有意识到指针必须从某处加载才能进行比较。

英文:

> Why is it possible in C++ that a mere check for nullptr causes such an exception ?

It isn't. The check is not the problem here.

> I mean I am not trying to use the object, I am just checking is the addresss a nullptr.

The pointer is a member of another object, which you haven't shown. Most likely this (and literally this) is where the problem lies.

When you say

> I have a class that has some FFmpeg object as member variable

it tells us that the expression

(formatContext != nullptr)

is really

(this->formatContext != nullptr)

and the load of the member variable from this is something that could cause an access violation: if either this is not a valid pointer (because you incorrectly cast something to a pointer to your class or because prior Undefined Behaviour already trashed your process) or potentially if this was already deleted.

Your intuition was correct that the comparison is unlikely to be a problem (the rare exception being platforms with pointer trap representations) - you were just missing the fact that the pointer had to be loaded from somewhere to be compared.

答案2

得分: 0

"Invalid argument"异常可能是因为&formatContext不是指向有效对象的指针的指针,因此它是avformat_close_input函数的无效参数。
所以异常可能来自该函数(使用调试器),而不是nullptr检查,该检查应始终有效,因为您正在比较两个指针(如果未重载&运算符,则为两个数字)。

英文:

The Invalid argument exception might be because &formatContext is not a pointer to a pointer to a valid object and as such it is an invalid argument to the avformat_close_input function.
So the exception might come from that function (use a debugger) and not from the nullptr check that should always be valid as you are comparing two pointers (two numbers if the & operator is not overloaded).

huangapple
  • 本文由 发表于 2023年6月19日 23:11:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76507928.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定