2017-12-10 3 views
2

私はこれらの2つの簡単な機能を持っています。オブジェクトを参照渡しするので、func1は良い解決策だと思いました。私の教科書は最高の解決策の答えとしてfunc2を与えました。これは、heapstrの割り当てを解除していないためですか?メインでheapstrと宣言して関数に渡すと、後で削除することができますか?ヒープオブジェクトまたは戻り値への参照を返すべきですか?

#include <iostream> 

using namespace std; 


string& func1(const string &str) { 
    string* heapstr=new string(); 
    for (int i = 0; i < str.size(); ++i) { 
     *heapstr += str[i]; 
    } 
    return *heapstr; 
} 

string func2(const string &str) { 
    string heapstr; 
    for (int i = 0; i < str.size(); ++i) { 
     heapstr += str[i]; 
    } 
    return heapstr; 
} 

int main() { 
    cout << func1("aaa") << endl; 
    cout << func2("aaa") << endl; 
} 
+2

価値!常にデフォルト値として値を優先します!その漏れについて話すことさえありません。 – StoryTeller

+0

'func2'、より安全で速い(https://stackoverflow.com/questions/161053/which-is-faster-stack-allocation-or-heap-allocation) – macroland

+0

プレーンなポインタを使用する場合は、あなたが本当にそうする正当な理由があれば。 – Simon

答えて

5

ヒープオブジェクトまたは戻り値を参照する必要がありますか?

戻り値。

多くの理由がありますが、実際にパフォーマンスに関係するものはありません。コンパイラは最適化を行う上で十分であり、そうでない場合でもほとんどのプログラムはI/Oにバインドされています。ファイルやネットワークソケットからのデータを待つ時間は、CPUの処理に費やされる時間ではなく、すべてのパフォーマンスを引き上げます。

は、例えば参照してください"Return containers by value (relying on move or copy elision for efficiency)"で言うハーブサッターとビャーネ・ストロヴストルップによる「C++コアガイドライン」、:コードを簡素化し、明示的なメモリ管理の必要性を排除するために

理由

。あなたの二つの機能については

...

私の教科書には、最善の解決策のための答えとしてfunc2を与えました。これは、heapstrの割り当てを解除していないためですか?

メモリリークは問題の1つです。しかし、重要な点は単純で、エラーが起こりにくいということです。すべて約正解、スピードではありません。代わりにintを返すことができる場合はint*を返さないでしょうか?私はmainheapstrを宣言してから関数に渡された場合ので、私は後でそれを削除することができました何

コードにメモリリーク、クラッシュ、および未定義の動作の可能性があります。コードレビューでは、それは長くなるし、書きにくく、読みにくく、保守が難しく、デバッグが難しく、正当化するのが難しくなります。代わりに、あなたは絶対に何も得られません。

+0

あなたのような人が私よりも優れた答えを書くことを続けているなら、私はどのように10,000人の代理人に通うつもりですか? –

1

これは教科書の一例ですので、あなたはそれが(その目標は、あなたや安全なプログラミングパターンを?!使用してメモリ使用量を最小限にすることである)を正確に表示するように望んでいるunderestandし、そのコンテキストを考慮すべきです。しかし、二人はヒント

  1. あなたがメモリを割り当てるnew演算子を使用

    は、あなたがdeleteを使用して割り当てを解除しなければなりません。コードのheapstrのメモリリークはfunc1です。
  2. さらに現実的なプロジェクトでは、メソッド間でオブジェクトを共有することは安全ではありません。その管理(つまり、現在これを変更している人や、オブジェクトが長く必要ないときにメモリの割り当てを解除する責任がある人)は難しくなりました。

PS:私はC++ 17を持っていませんが、以下のように最適化します。詳細は@BoPerssonのコメントを参照してください。

PS:スタックの割り当ては高速ですが、例ではfunc2 returnでコピー操作があります。あなたの例では@Jive Dadsonが何の違いによるOTコンパイラの最適化がされていないが、一般的なケースでは、コード

#include <iostream> 
#include <string> 
using namespace std; 


string& func1(const string &str) { 
    string* heapstr = new string(); 
    cout << "func1 " << heapstr << endl; 
    for (int i = 0; i < str.size(); ++i) { 
     *heapstr += str[i]; 
    } 
    return *heapstr; 
} 

string func2(const string &str) { 
    string heapstr; 
    for (int i = 0; i < str.size(); ++i) { 
     heapstr += str[i]; 
    } 
    cout << &heapstr << endl; 
    return heapstr; 
} 

int main() { 
    string a = func1("aaa"); 
    string b = func2("aaa"); 
    cout << "main " << a << endl; 
} 

PS以下の仮定言ったように:(@Jive Dadsonがあなたの例には差がありませんが、言ったようにin mine)パフォーマンスを実行時間として定義すると、おそらくfunc1になります。また、パフォーマンスをメモリ使用量として定義すると、func1。パフォーマンスを良いプログラミングパターンと定義すると、func2。完全にfunc2がより好ましい。

+0

func1には、ヒープ上にポインタと文字列があります。 func2には文字列しかありません。それは*少ない*メモリです。すでにほとんどのコンパイラはfunc2の戻り値をコピーしませんが、 'b'に直接作成します。 C++ 17では、このコピーエリートが必須になりました。 –

+0

@BoPersson _...すでに大部分のコンパイラ... _私はC++ 17がほとんどのコンパイラとして数えられると思っています。私はそれをしないVS17(それは11以上を使用する)でそれをチェックする。最初の部分については、コンパイラが最適化を前提としていれば正しいです。あなたのメモにも感謝します。私は自分の答えを更新する。 –

+0

コピーエリートは常に許可されているので、しばしば動作します。 g ++とclangの最新リリースは既にC++ 17を実装しています。そしてVS2017は、[バージョン15.6のプレビュー](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-html)で実装されたコピーelisionをちょうど得ました。プレビューrelnotes)。 –

2

テキスト帳は正しいです。 (Shocker。)

func1は、func2と異なる点ですべて不良です。そのオブジェクトがどのように削除されるかに関係なく、ヒープからオブジェクトを割り当てます。次に、新しいオブジェクトへの参照を返し、削除に使用されていたポインタを隠します。実際、Func1はおそらく少し遅いでしょう。いずれにしても、私の後ろに「早期の最適化を避ける」と暗唱してください。

標準テンプレートライブラリの出現以来、多くの月前に、new演算子を使用することはほとんど決してありません。私が最後にオペレータnewを使用したのはcaだった。 2003年に、私はunique_ptrとして現在知られているものと同等のものにポインタをラップしました。新しいオペレーターを使用する前に、スマートポインターとRAIIに関するすべてのことを学んでください。

関連する問題