指针正常工作然后看似无故中断

Pointer Works And Then Breaks Seemingly Without Reason

为什么我在分配指针后可以访问对象中保存的数据而我在分配函数的范围内,但是一旦我尝试通过相同的指针访问相同的值但在外部那个功能?

指针是成员函数,在函数内部赋值。在函数中,它工作正常。但是,当我从该函数中调用另一个使用 class 范围的函数时,指针行为不正常,呈现垃圾数据。为什么?

代码:

#include <iostream>

class Object{
public:
    Object(  ) { std::cout << "Object constructor called." << std::endl; }
    Object( const Object &in ) { i = in.i; std::cout << "Object copy constructor called." << std::endl; }
    ~Object(  ) { std::cout << "Object destructor called." << std::endl; }
    int i;
};

class ObjectManager{
public:
    Object * retObject(){
        Object *myObject = new Object;
        myObject->i=55;
        return myObject;
    }
};

class LogicManager{
public:
    LogicManager(){
        myObjectManager = new ObjectManager;
    }
    ~LogicManager(){
        delete myObjectManager;
    }
    Object * retObject(){
        return myObjectManager->retObject();
    }
private:
    ObjectManager *myObjectManager;
};

class Viewer{
public:
    ~Viewer(  ) { if( myObject ) { delete myObject; } }
    void ptrinObject( LogicManager * inLogic ){
        myObject = inLogic->retObject();

        std::cout << "Got path size of " << myObject->i << std::endl;       //correct
        std::cout << "Got path size of " << retObjectVal(  ) << std::endl;  //0?!?!?!?
    }
    int retObjectVal(  ) { myObject->i; }
private:
    Object *myObject;
};


int main(){
    LogicManager myManager;
    Viewer myViewer;
    //myViewer.cpyinObject( &myManager );
    myViewer.ptrinObject( &myManager );

    return 0;
}

输出:

Object constructor called.
Got path size of 55
Got path size of 861280848
Object destructor called.

Viewer class 中,您缺少 return 语句:

int retObjectVal( ) { return myObject->i; }

应该可以。

你所拥有的是一种方法,它的一些分支在没有返回值的情况下脱落。这会导致未定义的行为。您只是将 "myObject->i;" 评估为一个语句。


您可能应该解决的另一个问题是您的对象指针不为任何人所有,也不会在任何地方被删除。也就是说,您正在删除 ObjectManagerdelete 底层对象本身无处可去。您可能应该弄清楚那里的所有权模型,让某人跟踪这些指针,并在适当的时候 delete 它们。

问题是:

int retObjectVal(  ) { myObject->i; }

该函数中没有 return 语句。你只是有一个没有副作用的表达。结果,我们 运行 进入 §6.6.3/2:

Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

returns 是未定义的行为,所以它最终会返回一些垃圾。做到这一点:

int retObjectVal() { return myObject->i; }

这是一个容易犯的错误,这就是为什么您应该始终尝试使用尽可能高的警告设置进行编译。例如,在没有标志的 gcc 上,我没有收到任何警告。但是使用 -Wall,我得到:

warning: statement has no effect [-Wunused-value]

warning: no return statement in function returning non-void [-Wreturn-type]

首先,您没有初始化 Viewer::myObject 所以如果您只是

void something() {
    Viewer v;
}

您最终可能会尝试删除无效指针。

myViewer.cpyinObject( &myManager );
myViewer.ptrinObject( &myManager );

这两个函数都会创建一个新的 Object,但都不会检查是否已经分配了一个(内存泄漏)。然后,他们立即忽略创建的新对象,而是分配另一个由 ObjectManager 分配的新 Object(更多内存泄漏)。

最后,Viewer::retObjectVal 实际上并没有具体 return 一个值,因此您收到 "junk off the end of the function"。

我建议您查看编译器警告,因为任何明智的编译器都会警告您我提到的第一个和第三个问题。