当指向删除和指向不同的对象时,C++ 中的 Seg 错误指针

Posted

技术标签:

【中文标题】当指向删除和指向不同的对象时,C++ 中的 Seg 错误指针【英文标题】:Seg Faulting Pointers in C++ when pointing deleting and pointing to a different object 【发布时间】:2019-12-23 17:11:34 【问题描述】:

我开始在 C++ 中使用指针,我觉得我一定错过了 C 和 C++ 之间的一个关键元素。

我在一个类中有一个成员函数,它进行比较然后更改指针指向的内容:

void thisClass::largerSmallerSetter(int leftSize, int rightSize, matrix& leftMatrix, matrix& rightMatrix, matrix* largermatrix, matrix* smallerMatrix)

    if(leftSize >= rightSize)
    
        *largermatrix = leftMatrix;
        *smallerMatrix = rightMatrix;
    
    else
    
        *largermatrix = rightMatrix;
        *smallerMatrix = leftMatrix;
    

最初我的电话是:

matrix* largerSized = nullptr;
matrix* smallerSized =  nullptr;

largerSmallerSetter(LeftMatrix.getNumPieces(), RightMatrix.getNumPieces(), leftMemory, rightMemory, largerSized, smallerSized);

这会产生错误。这是因为 largeSized 和 smallSized 位于地址 0x0。

所以我想我会确保使用初始化指针。

matrix* largerSized = new matrix();
matrix* smallerSized = new matrix();

但是,这个新矩阵完全没用,所以我想摆脱实际的“新矩阵”,我只想让指针指向一个现有的。所以我添加了删除调用来删除对象。当我尝试将指针重新分配给不同的对象时,我得到一个段错误。

现在在 C 中,当我使用 malloc 创建一个指针时,我能够释放该指针。并且指针仍然存在,我可以指向其他地方。

有没有一种方法可以完成我想要的事情,而不会创建一堆只会挂在内存中并导致内存泄漏的对象?

我考虑过使用 std::shared_ptr。但是当我重新分配指针时,我担心当它到达范围的末尾时,它会尝试删除我指向的对象,该对象是在更高的范围内创建的并且需要继续存在。所以我不一定对智能指针感兴趣。

我尝试的另一件事是:

void thisClass::largerSmallerSetter(int leftSize, int rightSize, matrix& leftMatrix, matrix& rightMatrix, matrix* largermatrix, matrix* smallerMatrix)

    if(leftSize >= rightSize)
    
        largermatrix = &leftMatrix;
        smallerMatrix = &rightMatrix;
    
    else
    
        largermatrix = &rightMatrix;
        smallerMatrix = &leftMatrix;
    

但这一切的作用是,当作用域结束时,传入的指针会恢复到调用函数之前的状态。

【问题讨论】:

【参考方案1】:

让我们看看你的代码做了什么。

*largermatrix = leftMatrix;

它取消引用largermatrix(从而获得指针指向的那块内存)并尝试使用赋值运算符用leftMatrix的内容填充它(如果您有自定义重载,则可以是自定义操作那个运营商)。因此,如果largermatrix 没有指向任何内容,您将遇到您描述的问题。

另一方面,

largermatrix = &leftMatrix;

这将分配largermatrix 指向leftMatrix 的位置,这就是你想要的。但是,由于largermatrix 是一个局部变量,因此更改不会传播到调用者。因此,largermatrix 应该是对指针的引用。

void thisClass::largerSmallerSetter(int leftSize, int rightSize, 
                                    matrix& leftMatrix, matrix& rightMatrix,
                                    matrix*& largermatrix, matrix*& smallerMatrix)

顺便说一句,函数不会更改的其他引用参数是常量引用,如下所示:

void thisClass::largerSmallerSetter(int leftSize, int rightSize, 
                                    const matrix& leftMatrix, const matrix& rightMatrix, 
                                    matrix*& largermatrix, matrix*& smallerMatrix)

【讨论】:

【参考方案2】:

我在一个类中有一个成员函数,它进行比较然后更改指针指向的内容

不,您有一个分配给指针指向的对象的函数* 运算符,在这种情况下,dereferences 产生指向对象的指针。如果指针未指向对象,则其行为未定义。

但这一切的作用是,当作用域结束时,传入的指针会恢复到调用函数之前的状态。

不,传递给函数的原始指针从未改变。指针是对象,并且与所有对象一样,默认情况下按值传递。这意味着,例如,largerSizedlargermatrix 是完全独立的对象。它们唯一的关系是,当您调用函数时,它们最初具有相同的值。更改largermatrix 的值不会修改largerSized 的值。如果你想让你的函数中的赋值修改传递的对象,你需要传递一个引用:

void thisClass::largerSmallerSetter(int leftSize, int rightSize,
                                    matrix& leftMatrix, matrix& rightMatrix,
                                    matrix*& largermatrix, matrix*& smallerMatrix)
// passed by reference --------------------^----------------------^

注意:这也适用于 C。 C 没有引用,但您需要传递一个指向指针的指针,以便在函数内修改调用范围内的指针。

【讨论】:

【参考方案3】:

您可以使用多种方法来比较两个矩阵:

    更好的选择是返回最小矩阵的地址。例如,

    matrix *thisClass::largerSmallerSetter(int leftSize, int rightSize, matrix& leftMatrix, matrix& rightMatrix)
    
        if(leftSize >= rightSize)
            return &rightMatrix;
        return &leftMatrix;
    
    

    您可以在C++ 中重载比较运算符

    bool operator<(const matrix& a, const matrix& b)
    
        return a.getNumPieces() < b.getNumPieces();
    
    

    您可以在 C++ 中使用指针到指针。

    void thisClass::largerSmallerSetter(int leftSize, int rightSize, matrix& leftMatrix, matrix& rightMatrix, matrix** largermatrix, matrix** smallerMatrix)
    
        if(leftSize >= rightSize)
        
            *largermatrix = &leftMatrix;
            *smallerMatrix = &rightMatrix;
        
        else
        
            *largermatrix = &rightMatrix;
            *smallerMatrix = &leftMatrix;
        
    
    

    你可以有引用指针。

    void thisClass::largerSmallerSetter(int leftSize, int rightSize, matrix& leftMatrix, matrix& rightMatrix, matrix*& largermatrix, matrix*& smallerMatrix)
    
        if(leftSize >= rightSize)
        
            largermatrix = &leftMatrix;
            smallerMatrix = &rightMatrix;
        
        else
        
            largermatrix = &rightMatrix;
            smallerMatrix = &leftMatrix;
        
    
    

我对你的问题的评论:

我在一个类中有一个成员函数,它进行比较然后更改指针指向的内容:

要更改任何对象的值,您需要将其作为引用传递或作为指针传递。在您的情况下,您需要更改指针的值,然后您需要传递 pointer as reference 或传递指针的地址。否则,您的函数将更改它自己的本地指针副本。

这会产生错误。这是因为 largeSized 和 smallSized 位于地址 0x0。

这是因为在您的函数中,您试图将一个矩阵复制到指针所指向的矩阵(largermatrixsmallerMatrix)。但是,它们不指向任何有效对象。您需要使用new 动态分配对象或传递分配在其他地方的预分配矩阵的地址。

【讨论】:

以上是关于当指向删除和指向不同的对象时,C++ 中的 Seg 错误指针的主要内容,如果未能解决你的问题,请参考以下文章

当向量在内部类中时,如何删除指向对象的向量指针

当函数返回时,指向超出范围的对象的 C++ 指针 - 为啥会这样?

当指针指向的对象被另一个类的实例删除时重新分配指针

我是否正确删除了指向对象的向量?

删除指针数组而不删除内存中的指向对象?

C++随笔:常量指针和指针常量