11

そのため、私は常に C++ ポインターと ... 他のポインターの名前が何であれ、少しあいまいでした。お気に入り、

Object* pointer = new Object();

対。

Object notpointer();

2つ目はおそらくポインターが関係していることはわかっていますが、基本的にはポインターではありません。(実際には何と呼ばれているのですか?)

さらに、最初のものについては、電話する必要があると思います

delete pointer;

それをやり終えたら、ある時点でそうですよね?もう一つは、気にする必要はありません。最初のものはヒープに割り当てられていますが、2番目のものはスタックに割り当てられており、メソッドが戻ると消えます。

しかし、関数から何か (プリミティブではない) を返す場合はどうでしょうか?

良い例は、Should I return std::strings? に書かれています。:

std::string linux_settings_provider::get_home_folder() {
    return std::string(getenv("HOME"));
}

前に書いたように、文字列はスタックに割り当てられ、関数が戻ったときに解放されるはずですよね? しかし、誰もそれについて何も言わなかったので、うまく機能していると思います。なんで?

一般的に、次の違いは何ですか

return new std::string("pointer");

return std::string("not-pointer");

?

また、両方が機能すると仮定すると、2 つの長所と短所は何ですか?

4

2 に答える 2

14

ポインターで戻るときは、動的に割り当てられたオブジェクトを示す方法で返す必要があります (つまり、スタック オブジェクトへのポインターを返すと、後で逆参照された場合に未定義の動作が発生します)。お気づきのように、そのオブジェクトを明示的に削除する必要があるため、これによりメモリリークが発生する可能性があります。

一方、値で返す場合 (つまり、2 番目のスニペット) は、スタック オブジェクトから返すオブジェクトを、戻り値を受け取るオブジェクトにコピーすることになります。

std::string res = get_home_folder(); // std::string gets copied into res

コンパイラはこれを最適化して、戻り値の最適化によるコピーを回避できます。

于 2013-09-22T01:48:38.597 に答える
3

これは実際には戻りObject notpointer();値と呼ばれる関数を宣言しているため、実際には書きたくなかったと思います。問題のエンティティが呼び出しであることを意味する場合。実際、値はスタックに割り当てられるか、オブジェクトのメンバーである場合はオブジェクトに埋め込まれます。notpointerObjectObject notpointer;

何かを返す場合、返されるエンティティは、実際の戻り値が期待される場所にコピーまたは移動されます。戻り値が構築されると、ローカル オブジェクト、つまりスタック上のオブジェクトはスコープ外になり、破棄されます。とにかくローカルオブジェクトがなくなることを考えると、コピーコンストラクターやデストラクタに副作用がある場合でも、コンパイラーはコピーを省略して正しい場所にオブジェクトをすぐに構築することができます。

あなたの2つのreturnステートメントの違いは

  1. 使用new std::string("pointer")すると、ヒープに割り当てられたオブジェクトを取得し、オブジェクトへのポインターを返します。そのポインターをリークするのは非常に簡単であり、適切なオブジェクトにすぐに配置することをお勧めしますstd::unique_ptr<std::string>

    return std::unique_ptr<std::string>(new std::string("pointer"));
    

    このようにして、ポインターはリークされません。もちろん、戻り値の型も astd::unique_ptr<std::string>ではなく aに変更しstd::string*ます。ヒープ割り当ては一般にかなり高価であることに注意してください。

  2. 使用するときstd::string("value")は、ローカル変数を返すだけです。コピーが省略され、戻り値が本来あるべき場所にすぐに構築される可能性は十分にあります。関連するすべてのオブジェクトが自動的に破棄されるため、リソースを管理する必要はありません。明示的なヒープ割り当てはなく、スタック割り当ては非常に高速です。

もちろん、与えられた例ではstd::string、どちらの場合も内部表現を実際に割り当てる必要があります。ポインターが返された場合、追加の内部割り当てがないことが保証されます。一方、std::string値を返し、それを実際にコピーする必要がある場合は、コピーのために内部メモリを割り当てる必要がある場合があります。つまり、大量のメモリ割り当てが必要になる可能性がある大きなオブジェクトを返す場合、値を返すアプローチでは、値をコピーする必要があるというリスクがあります。ただし、現在の C++ では、オブジェクトは最悪の場合に移動されます。つまり、C++03 の場合ほどオブジェクトのコピーに関する懸念はありません。

于 2013-09-22T01:56:35.570 に答える