2

すべてのクラスが実際に参照であるJavaでは、次のようにします。

Car getCar(int mileage)
{
  Car car = new Car();

  car.setMileage(mileage);
  return car;
}

C ++では、どうすればこれを行うことができますか?私はそれを参照に入れることができます:

void getCar(int mileage, Car& car)
{
  car.setMileage(mileage);
  return true;
}

または、新しいオブジェクトを作成できます。

Car* getCar(int mileage)
{
  Car* car = new Car;

  car.setMileage(mileage);
  return car;
}

ただし、呼び出し元は削除する責任もありcarます。

ポインタを返したくありません。車を返却したい:

Car getCar(int mileage)
{
  Car car;

  car.setMileage(mileage);
  return car;
}

ただし、もちろん、car関数が終了すると削除されるローカル変数です。

これを行うための一般的な「標準的な」方法は何ですか?どちらが最善の方法であり、その理由は何ですか?

4

4 に答える 4

4

コードの最後の部分は問題ありません-ローカル変数自体ではなく、ローカル変数の値を返しているため、(少なくとも理論的には)その値はローカル変数から呼び出し元の場所にコピーされます割り当てます。

これは基本的に、次のようなものがある場合と同じです。

int f() { 
    int x = 0; 
    return x;
}

繰り返しますが、値を返しています。値はたまたまローカル変数から取得されますが、変数ではなく値を返しています。

「少なくとも理論上」の部分に関する限り、ほとんどのコンパイラはこれを最適化できるため、実際にはコピーはまったく行われません。コンパイラがこのコピーをスキップできるようにするための特別なルールがいくつかあります。コピーが発生したときに外部から見える副作用が発生する場合でも (たとえば、コピーが発生しました)。

于 2012-05-02T03:41:18.553 に答える
2

最後の例は、オブジェクトを返す正しい慣用的な方法です。

Car getCar(int mileage)
{
  Car car;

  car.setMileage(mileage);
  return car;
}

はい、car関数の最後に削除されますが、返されたオブジェクトにコピーされる前ではありません。この関数は次のように呼び出すことができます。

{
    Car myCar;
    myCar = getCar(42);
}

carローカルなgetCarは、呼び出し元の環境の にコピーされますmyCar


ローカル変数への参照またはポインターを返すことはできません。これは間違っています:

Car& getCar(int mileage)
{
  Car car;
  return car;
}

これも間違っています:

Car* getCar(int mileage)
{
  Car car;
  return &car;
}

これらの各ケースでは、呼び出し元の関数が存在しないオブジェクトにアクセスできるようにしています。

ローカルへのポインターまたは参照を返してはなりません。ローカルのコピーを返すことができます。

于 2012-05-02T03:40:59.667 に答える
1
Car getCar(int mileage) {   Car car = new Car();    car.setMileage(mileage);   return car; }

C++ では、これを行うにはどうすればよいですか? 私はそれを参照に入れることができます:

void getCar(int mileage, Car& car) {   car.setMileage(mileage);   return true; }

はい - それは問題ありませんが、関数に対して何も返すことはできませんvoid

または、新しいオブジェクトを作成できます。

Car* getCar(int mileage) {   Car* car = new Car;    car.setMileage(mileage);   return car; }

ただし、呼び出し元は car の削除も担当します。

確かにそうですが、スマート ポインターを使用すると、より信頼性と利便性を高めることができます。

ポインターを返したくありません。車を返却したい:

Car getCar(int mileage) {   Car car;    car.setMileage(mileage);   return car; }

しかしもちろん、 car は関数が終了すると削除されるローカル変数です。

そうではありません - これは完全に機能します - car オブジェクトはvalue によって返されます。これは、呼び出し元が式で使用できることを意味し、他の場所にコピーするためのソースとしても使用できます。

一般的に、これを行う「標準的な」方法は何ですか? 最適な方法はどれですか?その理由は?

一般に、上記の最後のバージョンは「標準」の方法です。通常は十分に効率的で (最適化されたビルドで最適化されることが多い)、面倒なポインターを回避し、直感的でシンプルです。new確かに、それができる C++ から、いたるところに変数が必要な Java に移行するのは苦痛です。

于 2012-05-02T03:44:28.017 に答える
0

よく理解しておくべき重要な違いは、Java ではオブジェクトは参照によるものであり、そのアドレスによって識別されるということです。

C ++では、それらは「値」(のようなint)であり、...アドレスによって識別されます:-((これは、仕様がオブジェクトを呼び出す方法です)

イディオムが何を言おうと、あなたは決定を下さなければなりません: あなたにとって何が重要なのか: 値とアドレス?

同じ値Personを持つ2 つは同じ (現実世界の) personを表していますか、それとも 2 つの実在語の同音異義語person -s を表していますか? あなたのコンテキストでは、ポリモーフィズムはどのくらい重要ですか? (さまざまな派生によって表される「」には多くの種類がありますか)?namePerson

これは「イディオム」が言うことではありません。それはあなたが確立しなければならない規則です。

値を操作したい場合は、値で戻ります (注: ほとんどの場合、コピー オン リターンはコンパイラによって省略されるため、パフォーマンス リミッターではありません) が、ポリモーフィズムを忘れていました。ただし、オブジェクトにリソースが含まれている場合は、それらが「値による」パラダイムにも従っていることを確認してください。それ以外の場合は、リソースの所有権を適切に処理するために、コンストラクタ、デストラクタ、コピー コンストラクタ、ムーブ コンストラクタ、および割り当てをオーバーライドする準備をしてください。または...値によるリソースマネージャーを使用してそれらをラップします(スマートポインターでこれを行うことができます)。

アドレスを操作する必要があり、ポリモーフィズムが必要な場合は、オブジェクトをヒープに割り当て、ポインターを操作し、割り当て/割り当て解除を適切に管理する必要があります (最終的にはunique_ptrやのようなスマート ポインターの助けを借りてshared_ptr)。

どちらの場合にも一連のイディオムとパターンがありますが、最初のポイントは、どのモデルをターゲットにしているかを理解し、一貫して動作することです。

しかし、いずれにしても得られないことが 1 つあります。それは、C++ が「Java のように」なることはないということです。したがって、それをエミュレートしようとしないでください。値またはポインタ (参照による変更はあまりありません) によって、別の方法で考える必要があります。

于 2012-05-02T07:30:36.143 に答える