1. ホーム
  2. c++

[解決済み] C++で「オブジェクトを返す」方法とは?

2022-04-16 11:56:07

質問

似たような質問が多いのでタイトルは聞き覚えがあると思いますが、違う側面からの質問です(スタックに物があることとヒープに置くことの違いはわかります)。

Javaでは、常に"local"オブジェクトへの参照を返すことができます。

public Thing calculateThing() {
    Thing thing = new Thing();
    // do calculations and modify thing
    return thing;
}

C++で同様のことを行うには、2つのオプションがあります。

(1) オブジェクトを返す必要があるときは、参照を使用することができます。

void calculateThing(Thing& thing) {
    // do calculations and modify thing
}

そして、次のように使用します。

Thing thing;
calculateThing(thing);

(2) あるいは、動的に割り当てられたオブジェクトへのポインタを返すことができる。

Thing* calculateThing() {
    Thing* thing(new Thing());
    // do calculations and modify thing
    return thing;
}

そして、次のように使用します。

Thing* thing = calculateThing();
delete thing;

最初の方法を使えば、手動でメモリを解放する必要はありませんが、私にはコードが読みづらくなってしまいます。2つ目の方法の問題点は、「メモリ解放のために delete thing; というのは、あまりいい感じではないですね。コピーした値を返すのは非効率的なのでやりたくない(と思う)ので、ここで質問です。

  • 3番目の解決策(値をコピーする必要がない)はありますか?
  • 最初の解決策にこだわっても問題はないのでしょうか?
  • どのような場合に、どのような理由で、2番目の解決策を使うべきでしょうか?

どのように解決するのですか?

<ブロッククオート

コピーした値を返すのは非効率なので避けたい

証明しなさい。

RVOとNRVO、そしてC++0xのmove-semanticsを調べてみてください。C++03では、ほとんどの場合、outパラメータはコードを醜くするための良い方法であり、C++0xではoutパラメータを使うことで実際に自分を傷つけてしまうことになります。

きれいなコードを書き、値で返すだけです。もしパフォーマンスが問題なら、それをプロファイルし(推測をやめ)、それを修正するために何ができるかを見つけてください。それはおそらく、関数から何かを返すことではないはずです。


とはいえ、どうしてもそういう書き方をしたいのであれば、アウトパラメータにしたほうがいいかもしれませんね。動的なメモリ割り当てを避けることができるので、より安全で一般的に高速になります。ただし、関数を呼び出す前にオブジェクトを構築する必要があり、すべてのオブジェクトに対して常に意味があるわけではありません。

もしダイナミック・アロケーションを使いたいのであれば、最低限できることはスマート・ポインターの中に入れておくことです。(これはいずれにせよ常に行われるべきことです) そうすれば、何かを削除する心配はなく、物事は例外的に安全です、等々。唯一の問題は、とにかく値で返すより遅いということです。