我一直对我正在做的一些功课感到难过。
我正在研究一个名为“boxFactory”的函数,它将Box基类的指针返回给测试类。然后测试类从该指针调用print函数。
现在我正在尝试在我处理其他类型之前打印方格盒子。但是,当我运行下面的代码时,bptr-> print(os)会抛出一个异常:
“Assignment.exe中0x0091C512处的未处理异常:0xC0000005:访问冲突读取位置0xCCCCCCD0。”
Box * boxFactory(char c, int w, int h){
Box * b;
if(c == 'c')
{
CheckeredBox cb;
b = &cb;
b->setHeight(h);
b->setWidth(w);
return b;
}
return NULL;
}
测试类的代码段:
Box * bptr = boxFactory('c',5,3);
// Check print #7
os.str(""); //reset output holder
bptr->print(os);
t.test(os.str() == "x x x\n x x \nx x x\n", "print 5x3 checkered box from factory");
派生的Checkered类的打印函数:
ostream& CheckeredBox::print(ostream& os) const
{
//HEIGHT for loop
for (int i = 0; i < height_; i++)
{
bool isX; //is current space x or blank
//makes the every other line starts
if (i % 2 == 0)
{
isX = true;
}
else
{
isX = false;
}
//WIDTH for loop
for (int c = 0; c < width_; c++)
{
if (isX) //utilizes isX boolean
{
os << "x";
isX = false; //oscilates bool between spaces
}
else
{
os << " ";
isX = true; //continues oscilation
}
}
os << "\n"; //append new line after each row
}
return os;
}
答案 0 :(得分:3)
您在boxFactory函数中创建了CheckeredBox对象的自动实例。因此,当cb对象超出范围(如果是块)时,它将被销毁,并且您将返回被破坏对象的地址。这就是为什么当您尝试调用此指针的print方法时,会出现“Access Violation”错误。以下是您可以做的事情,以实现您想要的目标。
您需要使用new关键字在堆上构造CheckeredBox对象,然后从boxFactory函数返回它。在这种情况下,您的应用程序将工作,但问题仍然是谁应该删除您在堆上创建的对象。您可以在函数文档中指定调用者应该删除返回的对象,但如果您或其他人使用您的代码不够仔细,则很可能您的应用程序泄漏了内存。 您可以使用std :: auto_ptr来获取和转移对象的所有权,以便自动删除它。
std::auto_ptr<Box> boxFactory(char c, int w, int h){
std::auto_ptr<Box> b;
if(c == 'c')
{
CheckeredBox *cb = new CkeckeredBox();
cb->setHeight(h);
cb->setWidth(w);
b.reset(cb);
}
return b;
}
考虑到auto_ptr在新的C ++ 11标准中已弃用,您可以使用boost :: shared_ptr,std :: unique_ptr(仅限C ++ 11)或std :: shared_ptr(仅限C ++ 11)。
答案 1 :(得分:2)
if(c == 'c')
{
CheckeredBox cb;
b = &cb;
b->setHeight(h);
b->setWidth(w);
return b;
}
局部变量在堆栈中分配,当声明它们被声明的代码块退出时,相同的内存空间将用于覆盖它们的其他变量。
要动态分配对象,请使用new
运算符,它将分配堆中的对象。这些对象将在delete
之前可用(不要忘记这样做,否则你会得到内存泄漏)
b = new CheckeredBox();
// etc.
答案 2 :(得分:1)
您正在返回指向局部变量的指针。这是未定义的行为。
if(c == 'c')
{
CheckeredBox cb;
b = &cb;
b->setHeight(h);
b->setWidth(w);
return b;
}
一旦函数离开此cb
,if
超出范围,但您返回其地址。使用此地址会导致&#34;未定义的行为&#34;。您想要在堆上分配一个对象然后返回它。像下面的东西。
b = new CheckeredBox();