0

私は現在、C++ で関数を使用してオブジェクトを操作する方法を学習しています。これまでのところ、次の点に到達しています。

オブジェクトが潜在的に大きい場合は、それをローカル変数にしないでください。つまり、コピーの時間を節約するためにヒープに保持してください。

具体的には、以前には存在しなかったオブジェクトを作成する関数を使用しているシナリオに興味があります。関数がある場合に何をすべきかを示すために、次の小さな例をまとめました。

#include <iostream>
using namespace std;

struct obj {
    int first;
    int second;
};


void setFirstVersionA(int a, obj * s)
{
    s->first = a;
}

obj * setFirstVersionB(int a)
{
    //in Version B I am creating a new object in the function but have to run delete outside
    obj * s = new obj();
    s->first = a;
    return s;
}


int main(int argc, const char** argv)
{
    obj * myobj = new obj();
    setFirstVersionA(2,myobj);
    //now I have the new obj in *i
    cout << myobj->first;
    delete myobj;

    //this is an alternative to passing a pointer directly:

    //no need to re-declare the pointer as delete only erases the myobj data
    myobj = setFirstVersionB(3);
    //now I have the new obj in *i
    cout << myobj->first;
    delete myobj;

    return 0;
}

私が知る限り、両方の関数で同じ結果が得られます。

バージョン A の方が、new 宣言と delete 宣言が分離されておらず、完了後にオブジェクトを削除するのを忘れる可能性が低くなるため、私はバージョン A の方が気に入っています。しかし、それは戻り型 void であり、関数が何をするかを実際に確認する必要があるため (一般的には、他のファイルを読み取ることを意味します)、コードが読みにくくなっています。

私が変更したかった「もの」を返すので、バージョン B の方が好きです。したがって、この関数はその人 (この場合は obj ) を変更することがすぐにわかります。ただし、新規と削除を分離します。正直なところ、コードに一連の void 関数があり、それらが何をするかをすぐに確認しないよりもひどいことではありません。また、ここではローカル変数へのポインターを返さないことについて多くのことが書かれていますが、バリアント B では、オブジェクトは関数内で作成されますが、ローカル変数ではありません (ヒープにあるため)。右?

それを行うより良い方法はありますか?また、「以前には存在しなかったオブジェクトを作成する関数」は、コンストラクターのように聞こえます。:) おそらく、オブジェクトごとにコンストラクターを持つクラスを作成する必要がありますか?

アドバイスありがとうございます!

4

4 に答える 4

3

適切な方法は、おそらく、値を引数として受け取るコンストラクターを作成することです。

struct obj
{
    obj(int f) : first(f) {}
    // ...
};

// ...

obj myobj(2);

または、セッター関数を使用するには:

struct obj
{
    void set_first(int f) { first = f; }
    // ...
};

// ...

obj myobj;
myobj.set_first(2);

上記のメソッドはもちろん組み合わせることができるため、特殊なコンストラクターとセッター メソッドの両方を使用できます。

パブリックメンバー変数のみを持つ構造体を使用しているため、セッターメソッドはスキップされる場合があります。

于 2013-07-23T12:03:31.303 に答える
3

見つけたアドバイスを無視して、オブジェクトをスタックに割り当て、値で返す必要があります。C++、特に C++11 には、これを効率的にするための特定の最適化があります。古いオブジェクトが不要になり、コピーよりも効率的な処理を行う状況)。

于 2013-07-23T12:03:41.253 に答える
2

Java の世界 (obj * myobj = new obj();構文) から来ていると思います。C++ では正しいですが、必要がない場合はポインターを使用しないでください。

より良い(imo)アプローチは次のようになります。

int main(int argc, const char** argv){
    Obj myObject; // your object now exists, fully usable.
    myObject.setValue(42); //classic, java-like setter

    Obj mySecondObect(42); //even better when you know the value at construct time.
}

Obj の ctr は次のようになります。

Obj::Obj(int myValue) : _myVal(myvalue){}

この場合、属性はコンストラクター本体の前に初期化されます (C++ コンストラクター サイクルを参照)。

于 2013-07-23T12:10:42.237 に答える
1

あなたは C++ を学んでいるので、c++11 を学ぶことをお勧めします。その場合、スマート ポインター (std::unique_ptr など) について考える必要があります。あるいは、スタック上にアイテムを作成し、コンパイラーに自動破棄 (RAII (リソースの取得は初期化) の原則) を処理させることについてもっと考えておく必要があります。

そうすれば、新規/削除の潜在的なメモリ リークを回避し、より信頼性の高いコードを作成できます。

オブジェクトを作成する関数は通常ファクトリであるため、後でこれを行うためのよりクリーンな方法として boost:value_factory<> を見たいと思うかもしれません。

于 2013-07-23T12:07:51.663 に答える