
コピーコンストラクタが呼び出されていない?
class myclass
{
public:
int x;
myclass(const int& init_); //コンストラクタ
myclass(const myclass& init_); //コピーコンストラクタ
const myclass operator+(const myclass& rhs); //加算
const myclass& operator=(const myclass& rhs); //代入
};
と定義したクラスを使ってオブジェクトを生成するときに妙な挙動をしています。
myclass mc1(10);
myclass mc2 = 20;
myclass mc3(mc1 + mc2); //コピーコンストラクタが呼ばれるはず
このコードを実行した結果は、mc3(mc1+mc2)では自分で定義したコピーコンストラクタは実行されませんでした。
mc3(mc1 = mc2)と実行すれば、コピーコンストラクタが実行されたのですが、この違いはどこにあるのでしょうか。
そもそも、myclassとmyclass&は全く別のものなのでしょうか?
No.2ベストアンサー
- 回答日時:
規格の12.8の15節に載っている,コピーコンストラクタの省略ですね。
ISO/IEC 14882:2003 Programming languages - C++
12 Special member functions - 12.8 Copying class objects / 15
> When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.
(略)
> - in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value
> - when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
日本語版 (JIS X 3014 プログラム言語C++) の記述だと,以下のようになっています。
12 特殊メンバ関数 - 12.8 クラスオブジェクトのコピー
> 処理系は,ある基準が満たされれば,そのクラスオブジェクトのコピーによる構築を省略してよい。これは,このオブジェクトのコピーコンストラクタ 及び/又は デストラクタが副作用を持つ場合も含む。
(略)
> -返却値の型がクラスである関数の return 文の式が,関数の返却値の型と同じ cv 修飾なしの型の volatile でない自動記憶域期間のオブジェクトの名前の場合,自動記憶域期間のオブジェクトを直接関数の返却値として構築することで,コピー演算は省略できる
> -参照に結合していない一時クラスオブジェクトがそれと同じ cv 修飾なしの型をもつクラスオブジェクトにコピーされる場合,一時オブジェクトを直接そのコピー先に構築することで,コピー演算は省略できる。
前者は関数内のreturn文の話なので,今回は関係しません。
なので後者について,元のコードを見ていきます。
> const myclass operator+(const myclass& rhs); //加算
> myclass mc3(mc1 + mc2); //コピーコンストラクタが呼ばれるはず
・mc1 + mc2は参照に結合していない一時クラスオブジェクトを返す
・mc1 + mc2の一時クラスオブジェクトの型はconst myclassで,新たに構築されるmc3の型はmyclass
より,後者の条件を満たします。
この場合,省略は「allowed」 (JISでは「してよい」) なので,コンパイラは省略することも省略しないことも許されます。
# 副作用の有無によらないので,コピーコンストラクタの中で複雑なことをやっていても無視できます。
次に,
> const myclass& operator=(const myclass& rhs); //代入
> myclass mc3(mc1 = mc2);
・mc = m1は参照に結合しているクラスオブジェクトを返す
ので,後者の条件を満たしません。
コンパイラはコピーコンストラクタの呼び出しの省略が規格に許されていませんから,コンパイラはコピーコンストラクタを呼び出すコードを記述します。
No.1
- 回答日時:
コンパイラに依存する問題な気がします。
的外れな解答になったらすいません。たとえば、次のような実装が行われていて、
myclass::myclass(const int& init_)
{
// (A)
x = init_;
}
myclass::myclass(const myclass& init_)
{
x = init_.x;
}
const myclass myclass::operator+(const myclass& rhs)
{
return myclass(x + rhs.x);// (B)
}
で、以下のコードを実行したとき、
myclass mc1(10);
myclass mc2 = 20;
myclass mc3(mc1 + mc2);
// (C)
myclass mc3(mc1 + mc2); の実行の時に、上の(B)行の
myclass::myclass(10 + 20); // (const int& のほう)
が呼ばれた形跡があるのだけど、
”そのあとに myclass::myclass(const myclass& init_); が呼ばれると思ったが、呼び出されないのはなぜ???”
という話でしょうか?
もし、そうなら、上の(A) の位置のthisポインタの値と、(C)の行の mc3 のアドレス
が一致しているか見てみてください。
(デバッガで追えるならデバッガで、printfがログに使えるのなら)
myclass::myclass(const int& init_)
{
// (A)
printf("constructor:0x%p\n", this);
x = init_;
}
myclass mc1(10);
myclass mc2 = 20;
myclass mc3(mc1 + mc2);
// (C)
printf("mc3:0x%p\n", &mc3);
もし、アドレスが一致しているのなら、コンパイラによる
”局所オブジェクトの削除”の最適化が行われているのでは?と思います。
まさに回答して頂いた説明の内容を確認したところ、その通りの結果となりました。
(B)の所に直接コンストラクタを使用する形で、return myclass(x + rhs.x)と書いたときには、このオブジェクトがmc3のオブジェクトのポインタと同じになりました。
また、(B)を以下のように書くとコピーコンストラクタが呼び出されました。
myclass retv(x + rhs.x);
return retv;
今更書いても遅いですが、このプログラムはVisualStudio2008で作成しており、最適化を無効化して実験しました。最適化のオプションを付けると、下のコードでもコピーコンストラクタは呼び出されませんでした。
コンパイラ凄いですね......
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Access(アクセス) Vba Userformを前面に出すについて 3 2022/04/15 12:29
- Visual Basic(VBA) VBA This Workbookモジュールを別ファイルにコピーする方法 1 2022/09/14 01:51
- Visual Basic(VBA) エクセルのマクロについて教えてください。 4 2023/05/26 17:13
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
- JavaScript 入力フォームの javascript で メールアドレスの正規チェックをを行い、ボタンをクリックして 2 2022/04/27 16:06
- JavaScript WordPressのコンタクトフォーム7にて送信者の位置情報を送らせたい 2 2022/09/14 23:28
- JavaScript sessionStorageを調べています。 1 2023/06/20 12:41
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C++で*thisは何を指しているの...
-
Unity,C#、複数の子オブジェク...
-
EXCEL VBAにて動的にCheckBOXを...
-
パワーポイントのVBAでテキスト...
-
マルチプルインスタンスのメリット
-
ResultSet での問題
-
newは明示的にした方が良いのか?
-
VBA 同じ名前のオブジェクトを...
-
VBScriptで計算して出た値をク...
-
Google Apps Scriptの時刻の計算
-
ブラウザ上でEXCELの印刷...
-
BufferedWriterのcloseメソッド
-
配列について
-
空の文字列とnullと""
-
デザインパターンとは?
-
インデザインのテキスト回り込み
-
C#でフォームのオブジェクト名...
-
Object型からDouble型へのキャスト
-
VBAのWindowオブジェクトとWork...
-
findObjっていう関数は何をして...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
パワーポイントのVBAでテキスト...
-
Excelで =EMBED("Acrobat Docu...
-
VBA 同じ名前のオブジェクトを...
-
EXCEL VBAにて動的にCheckBOXを...
-
VBAのWindowオブジェクトとWork...
-
C#でフォームのオブジェクト名...
-
ビジュアルC++でボタンの有...
-
COMコンポーネントって何?
-
Object型からDouble型へのキャスト
-
時間帯判定をする。
-
newは明示的にした方が良いのか?
-
戻り値がクラスオブジェクト
-
ワイルドカード<?>と型パラメー...
-
error C2712: オブジェクト ア...
-
Accessの連結・非連結オブジェ...
-
CoCreateInstanceでエラーになる。
-
オブジェクトレベルとメタレベル
-
多人数のじゃんけんプログラム
-
Rangeオブジェクトを一時的に作...
-
ワードで画像をドロップすると...
おすすめ情報