1

オブジェクトを返す関数がありますが、オブジェクト自体またはオブジェクトへのポインタを返す必要があるので混乱していますか?

これが私の関数の例です:

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++を初めて使用するので、我慢してください。

4

3 に答える 3

5

このコードには複数の問題があります。C++ でコーディングする場合に理解すべき基本的な違いは、スタック割り当てとヒープ割り当てです。そうするとCImage img = CImage();、オブジェクトはstackに作成されます。このオブジェクトは、関数が終了すると自動的に破棄されます。ここで、このオブジェクトへのポインターを返すと、オブジェクトが既に破棄されているため、呼び出し元は無効なメモリ位置へのポインターを取得します。また、このオブジェクトのアドレスをベクターにプッシュしていますが、これも関数が終了すると無効になります。にも同じ問題がありfileNameます。

これを解決するには、関数の終了時にオブジェクトが破棄されないように、ヒープからメモリを割り当てる必要があります。newC++を使用してヒープにオブジェクトを割り当てることができます。したがって、コードは になりCImage* pImage = new CImage();ます。この場合、 を使用してメモリを解放するのはユーザーの責任であることに注意してくださいdeleteCImage*したがって、この手法を使用して関数を返すように変更できます。このポインターを vector にプッシュすることもできますImages。オブジェクトに割り当てられたメモリを解放するには、ベクトルをループして、各ポインターで明示的に call を呼び出すCImage必要があることに注意してください。Imagesdelete

より良いアプローチはstd::shared_ptr、この場合のように の呼び出しをdelete自動的に管理するスマート ポインターを使用することです。

于 2012-06-15T04:12:33.033 に答える
3

最初にポインター部分の修正:

CImage * img = new CImage();

コンパイラ エラーを修正します。

インスタンスの寿命について考えてみましょう。クラスのインスタンスは、スコープの最後に到達すると破棄されます。ここでは、関数の閉じ括弧です。

最初の例では、関数の最後で img を破棄 (およびメモリを解放) しますImages.push_back

返されたインスタンスの場合、呼び出しコードが次のような場合、変数のコピーが作成される可能性が最も高くなります。

CImage outterImage = myDocument.addImage(...);

outterImage は、img 自体ではなく、img のコピーである可能性が高いです。

詳細については、C++ でのインスタンスのライフ サイクルを確認してください。

于 2012-06-15T04:11:01.460 に答える
1

新しいポインターを初期化するには、newキーワードを使用する必要があります。

CImage * img = new CImage();

これにより、ヒープ (メモリの非ローカル部分) にメモリの一部が割り当てられ、CImageそこにオブジェクトが作成されます。次に、そのオブジェクトへのポインターを取得してCImage返し、関数が現在のスコープを離れた後でもオブジェクトにアクセスできるようにします。これはあなたがすべきことです。

ただし、そうすると、コードが返された後にオブジェクトCImage img = CImage();を参照できなくなることがあります。CImageこれは、( を使用せずに) ローカル オブジェクトを宣言するnewと、スタック (メモリの他の部分) に存在し、関数が戻るとすぐに破棄されるためです。つまり、オブジェクトへのポインターがあっても、オブジェクトがなくなるため、アクセスしようとするとセグメンテーション違反が発生します。

于 2012-06-15T04:10:59.663 に答える