Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

コピーされずに呼出し元の一時オブジェクトとなる返却値

タグ: C++ VS2005 gcc
struct Base { void func() const; };

// コピー不可
struct A : Base
{
	A(int n);

private:
	A(const A&);
};

// 右辺値のコピー不可
struct B : Base
{
	B(int n);
	B(B&);
};

// コピー可
struct C : Base
{
	C(int n);
	C(const B&);
};

const A A1() { return 1; }
const A A2() { return A(2); }
const B B1() { return 1; }
const B B2() { return B(2); }
const C C1() { return 1; }
const C C2() { return C(2); }

int main(int, char*[])
{
	A1().func();
	A2().func();
	B1().func();
	B2().func();
	C1().func();
	C2().func();
	return 0;
}
  • gcc 4.0.1 のコンパイルエラー

     In function ‘const A A1()’:
    9: error: ‘A::A(const A&)’ is private
    26: error: within this context
    9: error: ‘A::A(const A&)’ is private
    26: error: within this context
    26: error:   initializing temporary from result of ‘A::A(int)’
     In function ‘const A A2()’:
    9: error: ‘A::A(const A&)’ is private
    27: error: within this context
    9: error: ‘A::A(const A&)’ is private
    27: error: within this context
     In function ‘const B B1()’:
    28: error: no matching function for call to ‘B::B(const B)’
    16: note: candidates are: B::B(B&)
    15: note:                 B::B(int)
    28: error:   initializing temporary from result of ‘B::B(int)’
     In function ‘const B B2()’:
    29: error: no matching function for call to ‘B::B(B)’
    16: note: candidates are: B::B(B&)
    15: note:                 B::B(int)
  • VC8 のコンパイルエラー

    (27) : error C2248: 'A::A' : private メンバ (クラス 'A' で宣言されている) にアクセスできません。
            (9) : 'A::A' の宣言を確認してください。
            (4) : 'A' の宣言を確認してください。
    (29) : warning C4239: 非標準の拡張機能が使用されています : '引数' : 'B' から 'B &' への変換です。
            非定数の参照は左辺値へのみバインドされます。コピー コンストラクタで非定数への参照を指定できます。

A1() B1() は gcc 4.0.1 ではコンパイルエラーとなるが、 VC8 では通る。
普通に考えれば、これらは A2() B2() と同じ値を返すのだから、動作に違いが出るとは思えない。

『JIS X 3014:2003』6.6.3/2 return文

void でない型の《式》を持つ return 文は、値を返す関数でだけ使うことができ、その《式》の値が関数の呼出し元に渡される。 その《式》は、それが現れる関数の返却値の型に、暗黙に変換される。 return 文は、一時的オブジェクトの構築(12.2)及びコピーを伴うことがある。

メンバ関数 func() を呼ぶため、呼び出し元には関数の返却値をコピーした一時オブジェクトが生成される。
その際、RVO(戻り値最適化)が働いてコピーコンストラクタが呼ばれなかったとしても、関数が返す値をコピーするためのコピーコンストラクタは定義されていなければならない。

『JIS X 3014:2003』12.2/1 一時オブジェクト

一時オブジェクトの生成が避けられる場合(12.8)であっても、すべての意味規則上の制約は、一時オブジェクトが生成されたかのように遵守しなければならない。
コピーコンストラクタを呼び出さない場合であっても、アクセス可能性(11.)などのすべての意味規則の制約が満たされなければならない。

『JIS X 3014:2003』12.8/15 クラスオブジェクトのコピー

処理系は、ある基準が満たされれば、そのクラスオブジェクトのコピーによる構築を省略してよい。 これは、このオブジェクトのコピーコンストラクタ及び/又はデストラクタが副作用をもつ場合も含む。

よって、コピーコンストラクタを呼び出せない A1() B1() はコンパイルエラーにならなければならない……はず。
見方によっては、コピーを伴うことがあるという文は本当に(RVOとかいうレベルではなく)コピーしなくてもいいようにも思えるが……

まあなんにせよ、「暗黙の型変換で返したときだけ通る」とか不気味だし。
素直にこれは「通らない」ものと考えておこう。

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/93-9886dbfc
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。