我有返回对象的函数,但我很困惑,我应该返回对象本身还是指向对象的指针?
以下是我的功能示例:
CImage CDocument::AddImage(string Name, string fileName)
{
CImage img = CImage();
img.Name = Name;
img.Path = fileName;
img.IwImage = Iw2DCreateImage(&fileName[0]);
Images.push_back(&img);
return img;
}
这是正确的还是应该返回指向对象的指针:
CImage * CDocument::AddImage(string Name, string fileName)
{
CImage * img = new CImage();
img->Name = Name;
img->Path = fileName;
img->IwImage = Iw2DCreateImage(&fileName[0]);
Images.push_back(img);
return img;
}
虽然最后一段代码编译不正确,因为我收到了这个错误:
error C2440: 'initializing' : cannot convert from 'CImage' to 'CImage *'
我认为这可能是一个非常简单的问题。我对c ++很新,所以请耐心等待。
答案 0 :(得分:5)
这段代码存在多个问题,在C ++编码时要理解的基本区别在于堆栈分配和堆分配。执行CImage img = CImage();
时,会在堆栈上创建对象。当函数结束时,此对象自动销毁。现在,如果返回指向此对象的指针,则调用程序将获取指向无效内存位置的指针,因为该对象已被销毁。您还将此对象的地址推送到向量中,一旦函数结束,该向量也将无效。 fileName
也存在同样的问题。
要解决此问题,您需要从堆中分配内存,以便在函数结束时不会销毁对象。您可以使用C ++中的new
在堆上分配对象。因此,您的代码将变为CImage* pImage = new CImage();
。请注意,在这种情况下,您有责任使用delete
释放内存。因此,您可以使用此技术更改函数以返回CImage*
。您也可以将此指针推送到向量Images
。请注意,要释放为CImage
对象分配的内存,您需要遍历Images
向量并在每个指针上显式调用delete
。
更好的方法是在这种情况下使用智能指针,例如std::shared_ptr
,它将自动管理delete
的调用。
答案 1 :(得分:3)
首先修复指针部分:
CImage * img = new CImage();
修复编译器错误。
考虑实例寿命。类的实例一旦到达其范围的末尾就会被销毁 - 这里它是函数的右括号。
第一个例子将在函数末尾破坏(并释放内存)img - 这可能会导致意外行为,具体取决于Images.push_back
的实现。
对于返回的实例,如果调用代码看起来像这样,则很可能会创建变量的副本:
CImage outterImage = myDocument.addImage(...);
outterImage很可能是img的副本,而不是img本身。
有关详细信息,请查看C ++中的实例生命周期。
答案 2 :(得分:1)
要初始化新指针,您需要使用new
关键字。
CImage * img = new CImage();
这会在堆上分配一部分内存(内存的非本地部分),并在那里创建CImage
对象。然后它抓取指向该CImage
对象的指针并返回它,即使在函数离开其当前作用域之后,也可以访问该对象。这就是你应该做的。
但是,如果执行CImage img = CImage();
,您可能会发现代码返回后将无法引用CImage
对象。这是因为当你声明一个本地对象(不使用new
)时,它存在于堆栈(内存的另一部分)上,并在函数返回后立即被销毁。这意味着即使你有一个指向它的指针,对象也会消失,所以尝试访问它会给你一个段错误。