关于c++的拷贝构造函数.
书中写到:
在C++中,下面三种对象需要调用拷贝构造函数!
对象以值传递的方式传入函数参数
对象以值传递的方式从函数返回
对象需要通过另外一个对象进行初始化;
针对上面的第二条,按照书中例子写出如下代码:
#include <iostream>
using namespace std;
class Point
{
public:
Point(int xx = 0, int yy = 0) :x(xx),y(yy){}
Point(Point &p){
x = p.x;
y = p.y;
cout << "copy function is Called" << endl;
}
int GetX(){ return x; }
int GetY(){ return y; }
private:
int x, y;
};
Point fun()
{
cout << "fun() Called\n";
Point t(2, 2);
return t;
}
int main()
{
Point t1(1,1);
Point t2 = fun();
cout << t2.GetX()<< endl;;
}
以上代码能在visual studio 2013 环境 下顺利编译通过
输出为
fun() Called
copy function is Called
x is 2
当在g++环境下编译时,却出现了错误
C:\Users\Hale\Desktop\test1>g++ -std=c++11 test22.cpp -o test22
test22.cpp: In function 'int main()':
test22.cpp:30:17: error: no matching function for call to 'Point::Point(Point)'
Point t2 = fun();
^
test22.cpp:30:17: note: candidates are:
test22.cpp:8:2: note: Point::Point(Point&)
Point(Point &p){
^
test22.cpp:8:2: note: no known conversion for argument 1 from 'Point' to 'Point&'
test22.cpp:7:2: note: Point::Point(int, int)
Point(int xx = 0, int yy = 0) :x(xx),y(yy){}
^
test22.cpp:7:2: note: no known conversion for argument 1 from 'Point' to 'int'
C:\Users\Hale\Desktop\test1>g++ -std=c++11 test22.cpp -o test22
test22.cpp:8:15: error: invalid constructor; you probably meant 'Point (const Point&)'
Point(Point p){
^
没有匹配的方法?于是添加构造函数
Point(const Point &p){
x = p.x;
y = p.y;
cout << "const copy function is Called" << endl;
}
再次编译,成功!
结果如下
fun() Called
2
但是刚刚新增的构造方法的方法并没有被调用,但是结果是正确的。说好的作为函数返回对象会调用构造函数呢?
g++为什么会有这种处理?
书上未能找到相关答案,网上搜寻也没能获得满意答案!
質問 1
エラーの理由は、コピー コンストラクターのパラメーターの型が正しく書かれておらず、
リーリーconst
修飾子が欠落していることです。 C++ では、一時変数を非 const 参照にバインドできません。元の投稿者のプログラム内の関数Point fun()
の戻り値は一時変数であり、コピー コンストラクターPoint(Point &p)
のパラメーターは非 const 参照であるため、コンパイラーは一致する関数がないことを示すエラーを報告します。 。コピー コンストラクターのパラメーターが定数参照に変更されると、一時変数を通常どおりバインドできるため、コンパイルは成功します。例:質問 2
これは、C++ 標準で、コンパイラが特定の状況下で関数の戻り値のコピー/移動操作を最適化できると明確に規定されているためです。
ISO C++11 標準 §8.5/16 では次の内容が規定されています (文脈は省略):
を参照してください。§12.8/31 には次のようになります:
つまり、これは単なるコンパイラの最適化です。作成者は、Visual Studio のリリース モードを使用してコンパイルを試みることができ、g++ のようなコピー コンストラクターをスキップする必要があります。
関連情報を調べた結果、C++ 標準に [戻り値の最適化] があることがわかりました。
gcc/g++ がコピー コンストラクターを呼び出さない理由は、gcc/g++ が関連する操作を最適化し、不要なコピー操作を省略したためです。具体的な説明については、Zhihu で誰かが行った説明を参照してください:
GCC がこれを行います。構造体を返す必要がある関数の場合、呼び出し時に追加のアドレスが関数に渡されます。次に、関数は戻り値をこのアドレスに直接構築します。この利点は、追加のコピー構築を必要とせずに、戻り値が適切な場所に直接構築されることです。これは、不必要なコピー構築を回避する非常に賢い実装です。 GCC に高く評価してください! !
著者: Li Qimai リンク: https://www.zhihu.com/questio... 出典: Zhihu の著作権は著者に属します。商業的転載の場合は、著者に連絡して許可を得てください。非商業的転載の場合は、出典を明記してください。
Visual Studio のデバッグ モードをリリースに変更すると、これらの不要な操作も最適化されていることがわかりました
Results
fun() Called
x は 2
これで問題は解決しました。
私の記憶が正しければ、C++11 または C++14 は const なしで実行できるためです。以前は const が必要でしたが、実際にはこの制限は意味がありません。
実際にコピー コンストラクターを呼び出したのではなく、t2 に値を直接割り当てたため、次のようにコピー コンストラクターを使用する必要があります。
リーリー