0

我需要一些帮助来返回对堆中创建的对象的引用。我正在阅读一本名为 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;
}
4

2 回答 2

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;
    }

在那里,您将对新对象的引用提供给将对其进行初始化的函数(即为其成员分配一些值)。该对象从声明的那一刻起就已经存在(默认情况下仅由垃圾初始化),因此这也是合法的。这里也没有内存泄漏,因为您没有为任何新对象申请内存。

于 2013-10-20T07:18:34.957 回答
0
 SimpleCat * rCat;
 SimpleCat & rCat = TheFunction(&rCat);

我不认为这些台词会像你认为的那样做。

第一行声明了一个变量 rCat,它是一个指向一只猫的指针,但从不构造一只猫来配合它。第二个将不起作用,因为您要再次声明相同的变量。(不能有 2 个rCat对象)。

不过,我仍然不太确定您要做什么。

SimpleCat rCat;
TheFunction(&rCat);

并且不要这样做: rCat = new SimpleCat(...) 在 TheFunction 中,只需像您拥有它们一样执行 SetAge/SetWeight 调用。

没有泄漏,因为您从未调用过新的。当然,TheFunction 也不再需要返回任何内容,因为它只是修改了传入的对象。不过,我不确定这是否说明了作者试图达到的目的。

我认为为了证明作者想要什么,您可以将 TheFunction 更改为:

void TheFunction(SimpleCat& rCat) {
  rCat.SetAge(5);
  rCat.SetWeight(9);
}
于 2013-10-20T07:06:43.817 回答