0

ヒープで作成されたオブジェクトへの参照を返す際に助けが必要です。Sam's Teach Yourself C++ というタイトルの本を読んでいます。第 12 章で、著者はヒープ上のオブジェクトへの参照を返すことを紹介しています。この例はメモリ リークを示しており、作成者によると、解決策の 1 つは、呼び出し元の関数でオブジェクトを宣言し、それを参照によって 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;
}

2 回目の試行

#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 で初期化されている場合に限ります。したがって、ポインターが何らかの形でガベージを指している場合、これも問題を引き起こす可能性があります。

3 番目のバージョン (最も安全) は次のようになります。

    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番目は機能しません。(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 に答える