C++ C++`如果他似乎走错了路?

C++ C++`如果他似乎走错了路?,c++,if-statement,C++,If Statement,我在为一个非理性的if声明而挣扎 在C++文件中考虑此代码 if (coreAudioDevice) { delete coreAudioDevice; coreAudioDevice = nullptr; } coreAudioDevice = AudioDevice::GetDevice(defaultOutputDeviceID, false, coreAudioDevice, true); if (coreAudioDevice) { coreAudioDevic

我在为一个非理性的if声明而挣扎

在C++文件

中考虑此代码
if (coreAudioDevice) {
    delete coreAudioDevice;
    coreAudioDevice = nullptr;
}
coreAudioDevice = AudioDevice::GetDevice(defaultOutputDeviceID, false, coreAudioDevice, true);
if (coreAudioDevice)
{
    coreAudioDevice->setDefaultDevice(true);
    // we use the quick mode which skips initialisation; cache the device name (in AudioDevice)
    // using an immediate, blocking look-up.
    char devName[256];
    coreAudioDevice->GetName(devName, 256);

    AUDINFO ("Using default output device %p #%d=\"%s\".\n",
             defaultOutputDeviceID, coreAudioDevice, coreAudioDevice->GetName());
}
else
    AUDERR ("Failed to obtain a handle on the default device (%p)\n", coreAudioDevice);
在ObjC++文件中调用函数:

AudioDevice *AudioDevice::GetDevice(AudioObjectID devId, bool forInput, AudioDevice *dev, bool quick)
{
    if (dev) {
        if (dev->ID() != devId) {
            delete dev;
        } else {
            return nullptr;
        }
    }
    dev = new AudioDevice(devId, quick, forInput);
    return dev;
}
这将导致以下终端输出:

ERROR coreaudio.cc:232 [init]: Failed to obtain a handle on the default device (0x7f81a1f1f1b0)
显然,if不应该失败,因为coreAudioDevice假定为NULL,然后在else分支中为该变量打印一个非NULL值


我尝试了不同的编译器选项和不同的编译器(Clang4.0.1和5.0.1),显然我的代码中确实有些可疑之处。有什么想法吗?

好吧,至少我找到了一个理由,但还不明白

我在没有注意到编译器警告的情况下定义了这个方法(由于并发编译,多次打印了大量的弃用警告…):

事实上,没有返回值

注意,我在跳过的
if
块中调用了这个方法,所以理论上我从来没有机会这么做。顺便说一句,正是它让我发现了这个奇怪的问题

当我删除调用或按预期使方法无效时,问题就会消失


我认为这也解释了我所见过的非常奇怪的崩溃方式:不知何故,乐观主义者会因此而完全困惑。我很想把这称为编译器bug;我不使用方法返回值,所以流不应该受到任何影响。

函数返回到函数的结尾而不返回一个值是C++中的未定义行为。 见和

因此调用
setDefaultDevice()
可以合法地产生任何结果。当程序的控制流导致未定义的行为(即调用
setDefaultDevice()
)时,编译器可以自由地将程序编译成可以执行任何操作的可执行文件

在这种情况下,使用
coreAudioDevice
非零输入
if
块将导致UB。因此,优化编译器预见到了这一点,并选择将其转到
else
分支。这样,它可以完全删除第一个分支和
if
,以生成更优化的代码


如果没有优化,程序应该正常运行。

啊,对了。我是否应该将其理解为“可以自由构建一个除了感官之外什么都能做的执行官”?如果是这样的话,我以前的老板有一点禁止C++作为一个反常词(确切的词是法语,“萨莱特”)…

无论如何,我可以理解为什么当您不知道函数实际上没有在堆栈上放置返回值时,行为将是未定义的。你会在返回后从堆栈中弹出字节,把事情搞砸。(必要时读取堆栈的堆=])。我猜,如果您在没有优化的情况下运行此类代码,在良好的ole C中运行,或者在定义了错误方法的情况下运行,就会发生这种情况(因此,优化者无法知道它有错误)

但是,一旦您知道函数实际上没有返回值,并且您看到该值无论如何都不会被使用,您就应该能够发出不会弹出相应字节数的代码。注意,代码的行为符合预期。带有一个大的编译时警告。假定标准允许这样做,而不是优化整个污染区块,因为这样会更快。如果这确实是《铿锵》中所遵循的推理,那么它实际上不会激发信心


标准是否规定默认情况下这不能是错误?比起目前的行为,我当然更喜欢这样

return nullptr
行上放置断点时,您会看到什么?在调试程序中,这些信息应该是通过代码逐行的,非常有帮助的。考虑把括号放在<代码>其他< /代码>分支>。code>AUDERR可能是一个宏,可能正在扩展到多个语句。
AUDERR
扩展到什么?只是根据我认为您的代码试图做的推测:
if(dev->ID()!=devId){
块看起来可疑。如果
dev
指向的
AudioDevice
已经有您想要的ID,您是否应该返回
dev
而不是
nullptr
?它只在启用优化时才会执行此操作(
-O#
),并使用
-Wall
警告UB。
-fsanitize=undefined
在叮当声中为UB添加运行时检查。从技术上讲,这是一个错误,因为根据标准,它不是一个有效的程序。当然,从技术上讲,这是一个错误,由于对评估顺序的假设,它比UB有更好的理由。这是一个错误,可能是不应该这样提出它。毕竟,非可选函数参数有什么区别?稍微挑剔一下:这只适用于具有非
void
返回类型的函数,除了
main
(隐式返回0)之外。另外,不确定您是如何得出OP的第一个代码段是其函数中的最后一个内容的?
bool setDefaultDevice(bool isDefault)
{
    mDefaultDevice = isDefault;
}