我希望在返回对堆中创建的对象的引用时提供一些帮助。 我正在读一本名为Sam's Teach Yourself C ++的书,在第12章中,作者介绍了对堆上对象的返回引用。该示例说明了内存泄漏,作者说其中一个解决方案是在调用函数中声明对象,然后通过引用将其传递给TheFunction()。
这是一个例子:
// Listing 12.5
// Resolving memory leaks
#include <iostream>
class SimpleCat
{
public:
SimpleCat (int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat & TheFunction();
int main()
{
SimpleCat & rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "&rCat: " << &rCat << std::endl;
// How do you get rid of that memory?
SimpleCat * pCat = &rCat;
delete pCat;
// Uh oh, rCat now refers to ??
return 0;
}
SimpleCat &TheFunction()
{
SimpleCat * pFrisky = new SimpleCat(5,9);
std::cout << "pFrisky: " << pFrisky << std::endl;
return *pFrisky;
}
我的尝试:
#include <iostream>
class SimpleCat
{
public:
SimpleCat(int age, int weight);
~SimpleCat() {}
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
SimpleCat::SimpleCat(int age, int weight):
itsAge(age), itsWeight(weight) {}
SimpleCat* TheFunction(SimpleCat&);
int main()
{
SimpleCat * rCat;
rCat = TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
std::cout << "rCat: " << rCat << std::endl;
delete rCat;
rCat = 0;
system("PAUSE");
return 0;
}
SimpleCat* TheFunction(SimpleCat& rCat)
{
rCat = new SimpleCat(5, 9);
std::cout << "rCat: " << rCat << std::endl;
return rCat;
}
第二次尝试
#include <iostream>
using namespace std;
class SimpleCat
{
public:
SimpleCat(int age, int weight)
{
}
void setAge(int age)
{
itsAge = age;
}
void setWeight(int wgt)
{
itsWeight = wgt;
}
~SimpleCat() { cout << "Object is being deleted" << endl; }
int GetAge() { return itsAge; }
int GetWeight() { return itsWeight; }
private:
int itsAge;
int itsWeight;
};
//SimpleCat * TheFunction();
SimpleCat& TheFunction(SimpleCat* rCat)
{
rCat = new SimpleCat(5,9);
//pFrisky->setAge(5);
//pFrisky->setWeight(9);
return *rCat;
}
int main()
{
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
答案 0 :(得分:0)
SimpleCat * rCat;
SimpleCat & rCat = TheFunction(&rCat);
我不认为这些行会按照你的想法去做。
第一行是声明一个变量rCat,它是一个指向cat的指针,但从不构造一个cat来与它一起使用。第二个是不起作用,因为你再次声明相同的变量。 (不能有2个rCat
个对象。
SimpleCat rCat;
TheFunction(&rCat);
并且不要这样做: rCat = new SimpleCat(...) 在TheFunction中,只需像你拥有它们一样进行SetAge / SetWeight调用。
没有泄漏,因为你从未打过电话。当然,TheFunction不再需要返回任何东西,因为它只是修改传入的对象。但我不确定这是否证明了作者试图达到的目的。
我想要证明作者想要的是什么,你要将你的TheFunction改为:
void TheFunction(SimpleCat& rCat) {
rCat.SetAge(5);
rCat.SetWeight(9);
}
答案 1 :(得分:0)
这可能有效(在某种意义上说,编译),但实际上是错误的:
SimpleCat TheFunction()
{
rCat = new SimpleCat(5,9);
// do something with rCat if you want
return *rCat;
}
int main()
{
SimpleCat rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
在这里,您创建新对象并返回对它的引用以初始化另一个对象,这是合法的,因为默认情况下每个C ++类都有一个复制构造函数。 但是,你会在这里遇到内存泄漏,因为你创建了一个永远不会被删除的新对象。
这可以是更好的版本:
void TheFunction(SimpleCat*& rCat)
{
if (rCat!=NULL) delete rCat;
rCat = new SimpleCat(5,9);
// do something else with rCat if you want
return; //not required
}
int main()
{
SimpleCat * rCat = NULL;
TheFunction(rCat);
int age = rCat->GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
在这里,您通过引用初始化新指针(这也是合法的)。声明指针时,声明变量,该变量具有地址,但还没有合理的内容。您将该地址的引用提供给您的函数,因此您不必返回任何内容。在函数初始化参考后,您可以在主程序中使用它。 这里没有内存泄漏,但只要所有新指针都使用NULL初始化。如果您的指针以某种方式指向垃圾,这可能会导致问题。
第三个版本(最安全的)将是:
void TheFunction(SimpleCat& rCat)
{
rCat.age = 5;
rCat.weight = 9;
}
int main()
{
SimpleCat rCat;
TheFunction(rCat);
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
system("PAUSE");
return 0;
}
在那里你将新对象的引用提供给函数,它将初始化它(即为其成员分配一些值)。该对象自声明之时就已存在(默认情况下仅由垃圾初始化),因此这也是合法的。 此处也没有内存泄漏,因为您没有为任何新对象声明内存。