Calling non-static member function outside of object's lifetime in C++17

前端 未结 5 1589
无人及你
无人及你 2021-02-03 22:06

Does the following program have undefined behavior in C++17 and later?

struct A {
    void f(int) { /* Assume there is no access to *this here */ }
};

int main(         


        
5条回答
  •  醉梦人生
    2021-02-03 22:46

    I'm not a language lawyer but I took your code snippet and modified it slightly. I wouldn't use this in production code but this seems to produce valid defined results...

    #include 
    #include 
    
    struct A {
        int x{5};
        void f(int){}
        int g() { std::cout << x << '\n'; return x; }
    };
    
    int main() {
        try {
            auto a = new A;
            a->f((a->~A(), a->g()));
        catch(const std::exception& e) {
            std::cerr << e.what();
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    I'm running Visual Studio 2017 CE with compiler language flag set to /std:c++latest and my IDE's version is 15.9.16 and I get the follow console output and exit program status:

    console output

    5
    

    IDE exit status output

    The program '[4128] Test.exe' has exited with code 0 (0x0).
    

    So this does seem to be defined in the case of Visual Studio, I'm not sure how other compilers will treat this. The destructor is being invoked, however the variable a is still in dynamic heap memory.


    Let's try another slight modification:

    #include 
    #include 
    
    struct A {
        int x{5};
        void f(int){}
        int g(int y) { x+=y; std::cout << x << '\n'; return x; }
    };
    
    int main() {
        try {
            auto a = new A;
            a->f((a->~A(), a->g(3)));
        catch(const std::exception& e) {
            std::cerr << e.what();
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    console output

    8
    

    IDE exit status output

    The program '[4128] Test.exe' has exited with code 0 (0x0).
    

    This time let's not change the class anymore, but let's make call on a's member afterwards...

    int main() {
        try {
            auto a = new A;
            a->f((a->~A(), a->g(3)));
            a->g(2);
        } catch( const std::exception& e ) {
            std::cerr << e.what();
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    console output

    8
    10
    

    IDE exit status output

    The program '[4128] Test.exe' has exited with code 0 (0x0).
    

    Here it appears that a.x is maintaining its value after a->~A() is called since new was called on A and delete has not yet been called.


    Even more if I remove the new and use a stack pointer instead of allocated dynamic heap memory:

    int main() {
        try {
            A b;
            A* a = &b;    
            a->f((a->~A(), a->g(3)));
            a->g(2);
        } catch( const std::exception& e ) {
            std::cerr << e.what();
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    

    I'm still getting:

    console output

    8
    10
    

    IDE exit status output


    When I change my compiler's language flag setting from /c:std:c++latest to /std:c++17 I'm getting the same exact results.

    What I'm seeing from Visual Studio it appears to be well defined without producing any UB within the contexts of what I've shown. However as from a language perspective when it concerns the standard I wouldn't rely on this type of code either. The above also doesn't consider when the class has internal pointers both stack-automatic storage as well as dynamic-heap allocation and if the constructor calls new on those internal objects and the destructor calls delete on them.

    There are also a bunch of other factors than just the language setting for the compiler such as optimizations, convention calling, and other various compiler flags. It is hard to say and I don't have an available copy of the full latest drafted standard to investigate this any deeper. Maybe this can help you, others who are able to answer your question more thoroughly, and other readers to visualize this type of behavior in action.

提交回复
热议问题