1

Thinking in C ++-Bruce Eckelでこの特定の例を経験しました。ステートメント1(コメントで言及)とステートメント2は理解できましたが、関数の宣言と定義が返されなくても、ステートメント3を理解するのに苦労しました。コピーの目的でオブジェクトを返す必要があります。ここで実際に何が起こりますか?他の2つのステートメント(1と2)について、私が推測できるのはクラス内でコピーコンストラクターを指定したため、コンパイラーはビットコピーを防止し、代わりに、関数内で渡されたオブジェクトと関数によって返されるオブジェクトに対して定義されたコピーコンストラクターを介してビットコピーを処理します。関数の終了直前に、関数内の一時オブジェクトが戻り値としてコピーされてから破棄されます。私はこれで正しいですか?

#include <fstream>
#include <string>
using namespace std;
ofstream out("HowMany2.out");
class HowMany2 {
    string name; // Object identifier
    static int objectCount;
    public:
    HowMany2(const string& id = "") : name(id) {
        ++objectCount;
        print("HowMany2()");
    }
    ~HowMany2() {
       --objectCount;
       print("~HowMany2()");
    }
    // The copy-constructor:
    HowMany2(const HowMany2& h) : name(h.name) {
       name += " copy";
       ++objectCount;
       print("HowMany2(const HowMany2&)");
    }
    void print(const string& msg = "") const {
       if(msg.size() != 0)
       out << msg << endl;
       out << '\t' << name << ": "<< "objectCount = "<< objectCount << endl;
    }
};
int HowMany2::objectCount = 0;
// Pass and return BY VALUE:
HowMany2 f(HowMany2 x) {
    x.print("x argument inside f()");
    out << "Returning from f()" << endl;
    return x;
}
int main() {
    HowMany2 h("h");//statement 1 
    out << "Entering f()" << endl;
    HowMany2 h2 = f(h);//statement 2
    h2.print("h2 after call to f()");
    out << "Call f(), no return value" << endl;
    f(h);//statement 3
    out << "After call to f()" << endl;
}

Eckelによると、出力は次のとおりです。

HowMany2()
h: objectCount = 1
Entering f()
HowMany2(const HowMany2&)
h copy: objectCount = 2
x argument inside f()
h copy: objectCount = 2
Returning from f()
HowMany2(const HowMany2&)
h copy copy: objectCount = 3
~HowMany2()
h copy: objectCount = 2
h2 after call to f()
h copy copy: objectCount = 2
Thinking in C++ www.BruceEckel.com
Call f(), no return value
HowMany2(const HowMany2&)
h copy: objectCount = 3
x argument inside f()
h copy: objectCount = 3
Returning from f()
HowMany2(const HowMany2&)
h copy copy: objectCount = 4
~HowMany2()
h copy: objectCount = 3
~HowMany2()
h copy copy: objectCount = 2
After call to f()
~HowMany2()
h copy copy: objectCount = 1
~HowMany2()
h: objectCount = 0

また、関数呼び出しの前に戻り値を格納できるように、戻り値に追加のストレージを割り当てることができなかったのはなぜですか。参照を使用する代わりになりますか?前もって感謝します!!!

4

2 に答える 2

2

関数の戻り値が無視されるため、コピーコンストラクターの呼び出しはありません。
コピーが必要になる可能性がある場合でも、ほとんどのコンパイラーは、特定の状況下で コピーの省略によるコピーコンストラクターの呼び出しを回避できることに注意してください。

xは関数に対してローカルなオブジェクトであるため(値の受け渡しがあります)、x関数スコープ{ }が終了すると破棄されます。

于 2013-03-08T16:34:29.227 に答える
2

他の2つのステートメント(1と2)については、クラス内でコピーコンストラクターを指定したため、コンパイラーがビットコピーを防止し、代わりに関数内で渡されたオブジェクトに対して定義されたコピーコンストラクターを介して処理することを推測できました。関数によって返されるオブジェクトについて。関数の終了直前に、関数内の一時オブジェクトが戻り値としてコピーされてから破棄されます。私はこれで正しいですか?

C ++の場合:

  1. 一時オブジェクトは、返されたオブジェクトからmove-constructedです(move-constructorを定義しなかった場合、これはcopy-constructionになります)。それから、
  2. 戻り値が割り当てられるオブジェクトは、戻り値からmove-assigned(使用した場合t = f())またはmove-constructed(使用した場合)のいずれかですT t = f()(move-assignment演算子が定義されていない場合、move-assignmentはcopy-assignmentになります。 move-constructorが定義されていない場合、move-constructionはcopy-constructionになります。それから、
  3. 一時的なものは破壊されます。

関数の宣言と定義でコピー目的でオブジェクトを返す必要がある場合でも、戻り値がない場合、ステートメント3を理解するのに苦労しました。

戻り値を使用しない場合、コンパイラーがコピーコンストラクターを呼び出す本当の理由はありません。返されたオブジェクトは、関数から戻るときにスコープから外れるだけで、それがすべてです。

ここでcopy-constructionの呼び出しが表示された場合、これはおそらく、コンパイラが上記の手順2と3を最適化できなかったことが原因です(コンパイラは呼び出しを削除できますが、必須でありません)。

于 2013-03-08T16:38:07.140 に答える