使用嵌套类访问解引用指针异常

问题描述 投票:0回答:1

我正在用 C++ 进行编程,在处理包含指向父类的指针的子类时,我遇到了取消引用的指针异常。简化的代码是这样的:

class top {
public:
    int val = 0;
    class mid {
    public:
        top* parent;
        class low {
        public:
            mid* parent = nullptr;
            void addToVal() {
                parent->parent->val += 1;
            }
            low(mid* Parent) {
                parent = Parent;
            }
            low() {}
        };
        low child;
        mid(top* Parent) {
            parent = Parent;
            child = low(this);
        }
    };
    mid::low child;
    top() {
        child = (mid(this)).child;
    };
};
int main()
{
    top t = top();
    t.child.addToVal();
}

但是该代码的要点是,您有三个类,顶级类尝试访问中间类的子级,然后最低类尝试访问顶级类中的值。我知道错误来自这两行:

mid::low child;
child =(mid(this)).child;
但我不知道为什么执行此操作后该指针会被取消引用,因为指向父级的指针是在调用中间构造函数时定义的,如mid 构造函数也会调用 low 构造函数。有谁知道创建孩子时这里发生了什么?

c++ pointers
1个回答
0
投票

通过 GCC 使用

-fsanitize=address
运行它,得到:

=================================================================
==1==ERROR: AddressSanitizer: stack-use-after-return on address 0x79bea1c00060 at pc 0x0000004012be bp 0x7ffce7648020 sp 0x7ffce7648018
READ of size 8 at 0x79bea1c00060 thread T0
    #0 0x4012bd in top::mid::low::addToVal() /app/example.cpp:11
    #1 0x40120f in main /app/example.cpp:31
    #2 0x79bea3a29d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 962015aa9d133c6cbcfb31ec300596d7f44d3348)
    #3 0x79bea3a29e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 962015aa9d133c6cbcfb31ec300596d7f44d3348)
    #4 0x4010c4 in _start (/app/output.s+0x4010c4) (BuildId: 52657344baa840d03bd8657b741b84c6bfb25e30)

Address 0x79bea1c00060 is located in stack of thread T0 at offset 32 in frame
    #0 0x401541 in top::top() /app/example.cpp:25

  This frame has 1 object(s):
    [32, 48) '<unknown>' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return /app/example.cpp:11 in top::mid::low::addToVal()

问题的原因是

mid(this)
是暂时的。当它被构造时,它将一个指向自身的指针传递给
low
,并且需要该指针才能通过
top
访问
parent->parent
实例。

因此,将其复制到

top::child
后,临时
mid
值将被销毁,从而留下存储在
child.parent
中的悬空指针。尝试
top().child.addToVal()
然后尝试使用这个悬空指针,这会导致未定义的行为。

你应该重新考虑你的设计。如果

low
需要指向
top
的指针,并且
mid
通常是临时的,那么只需直接存储它,而不是存储
mid
:

class low {
public:
    top* parent = nullptr;
    void addToVal() {
        parent->val += 1;
    }
    low(mid* Parent) {
        parent = Parent->parent;
    }
    low() {}
};
© www.soinside.com 2019 - 2024. All rights reserved.