Why is destructor hanging

后端 未结 2 1344
野趣味
野趣味 2021-01-24 02:47

Below code was working fine. However, when I enable p=&b in GetValue, the code failed \"Debug Assertion Failed\". Why?

class A{
int         


        
2条回答
  •  南方客
    南方客 (楼主)
    2021-01-24 03:44

    Firstly, it is important that you only delete memory that was allocated using new. Currently, your class A stores a pointer p that isn't allocated using new, but you do delete p as if it had been. The result of this is undefined behavior, which means that your program is not guaranteed behave correctly, and very weird bugs should be expected.

    Secondly, in the function A::GetValue(int b);, the parameter b is a temporary variable. When GetValue is called, some space is made on the call stack to pass b's value, where it resides for the lifetime of the function. But after GetValue returns, b no longer exists there. While C++ allows you to store pointers to invalidated memory, you need to be careful to avoid using such a pointer.

    To make your class A work correctly takes a fair bit of touching up, but I'll try to explain as I go. While currently it doesn't seem to make much sense to store an int* pointer where a simple int member would do, I'll keep using the pointer to help your understanding, and let the managing of a raw pointer be a learning exercise.


    Most of the problems stem from A::GetValue(int). Here, you're storing the address of a temporary variable, and in a context where a new-ed pointer is expected. You should instead make sure to correctly allocate memory, and not store a pointer to the transient parameter b:

    A::GetValue(int b){
        if (p == nullptr){
            // if p is null, it needs to be allocated before being written to
            p = new int(b); // initialize the memory at p to have value b
        } else {
            // otherwise, p has already been allocated, and its old value can be overwritten
            *p = b;
        }
    }
    

    Another more subtle problem arises when you write the following code:

    A a1, a2;
    a1.GetValue(13);
    a2 = a1;
    

    What will happen after these lines is that the p member of a1 will be deleted twice, causing yet more undefined behavior. The culprit is the automatically generated copy assignment operator, which simply copies p from a1 to a2 by value. To fix it, you need to write your own copy assignment operator and copy constructor as follows. The copy constructor is a little complex because there are lots of different cases to be handled.

    class A {
        ...
        A(const A& other) : p(nullptr) {
            if (other.p){
                p = new int(*other.p); // allocate new int and initialize with other's value
            }
        }
        A& operator=(const A& other){
            if (p){
                // if this is managing a pointer
                if (other.p){
                    // if other is managing a pointer too, just copy value
                    *p = *other.p;
                } else {
                    // otherwise, since other is null, delete and make this null
                    delete p;
                    p = nullptr;
                }
            } else {
                // if this is not managing a pointer
                if (other.p){
                    // other is managing a pointer, time to allocate
                    p = new int(*other.p);
                }
                // nothing needs to be done if both are null
            }
        }
    

    The importance of doing this is explained in the Rule of Three.

提交回复
热议问题