C++ 即使派生对象不存在,指向派生对象的基指针也可以工作

C++ 即使派生对象不存在,指向派生对象的基指针也可以工作,c++,C++,我有一个简单的问题。据我所知,如果变量作用域结束,变量就会被销毁。但是在下面的情况下,即使派生函数被销毁,基指针仍然调用派生函数的虚函数。这是纯粹的运气,还是派生对象实际上不会被销毁,直到所有指向派生对象的引用/指针都没有被销毁 int main(int argc, char **argv) { Base *base_ptr; std::string value = "hello"; if ( value == "hello") { Deri

我有一个简单的问题。据我所知,如果变量作用域结束,变量就会被销毁。但是在下面的情况下,即使派生函数被销毁,基指针仍然调用派生函数的虚函数。这是纯粹的运气,还是派生对象实际上不会被销毁,直到所有指向派生对象的引用/指针都没有被销毁

int main(int argc, char **argv) {

    Base *base_ptr;

    std::string value = "hello";

    if ( value == "hello")
    {
        Derived der1;
        base_ptr = &der1;

    }
    else {
        DerivedNew der_new;
        base_ptr = &der_new;
    }

    base_ptr->printDerived();
    // this prints the virtual function of the derived object. I was hoping it to print the base object.
}

在最后一行中,您应该希望得到的是崩溃,因为您的base_ptr指向一个对象,该对象在其作用域结束后已被破坏

一般来说,这是一种未定义的行为。任何数量的指针(智能指针除外)都不能延长超出范围的对象的生存期


您的代码不会崩溃,可能是因为编译器生成的代码为您的函数“分配”堆栈帧,以包括所有执行路径上的所有对象,并且仅在从函数返回时“解除分配”它。因此,至少在函数结束之前,对象在技术上是完整的。此外,是否调用对象的析构函数也基本无关,因为它不会使对象所在的内存神奇地消失。

您正在访问一个已销毁的对象。 那是未定义的行为。根据定义,你的程序是没有意义的,编译器可以把它编译成任何它喜欢的东西


你有责任不写未定义的行为。编译器不需要警告你。

相关/ DUPE:C++编译器优化了代码,并删除了愚蠢的if语句。所以DerivedNew析构函数尚未调用。@VictorGubin好的,但我怎么能不让这种情况在编译时发生,你是说派生析构函数尚未调用?希望不是一种推荐的策略。有时,像-O3这样激进的编译器优化会使代码完全出乎意料地工作。在这种情况下,您可以执行类似#if defined(GNUC)&&!已定义(铿锵)#pragma GCC push#选项#pragma GCC optimize(“O0”)#endif//GNUC/*您的代码在这里运行*/#如果已定义(GNUC)&&!定义(叮当声)#pragma GCC pop_选项#endif//gnuc将原始指针更改为智能指针可以使代码合法吗?你能举个例子吗?我指的智能指针是std::shared_ptr,不,在这个例子中,将常规指针更改为shared_ptr不会使此代码合法,因为指向的对象仍然在堆栈上,而使对象超出其作用域的唯一方法是在堆上分配它。然而,这个问题是关于派生对象的基指针的,所以我不认为在这里添加一个关于智能指针的示例是合适的。谢谢,它给了我一点启示。鉴于我对你的答案投了赞成票,否决票是不合适的。