記事のディレクトリ
1.リファレンスとは何ですか?
参照は新しい変数ではなく、既存の変数のエイリアスです。コンパイラは参照変数の新しいメモリスペースを開かず、参照と参照変数はメモリスペースを共有します。
参照はオブジェクトに別の名前を付け、参照型は別の型を参照します。&dの形式で宣言子を記述して、参照型を定義します。ここで、dは宣言された変数名です。
int val = 100;
int &refval = val;//refval指向val(是val另一个名字)
int &refval2;//会报错:引用必须被初始化。
1.1参照特性
1.参照を初期化する必要があります
Q1:なぜ参照を初期化する必要があるのですか?
通常、変数を初期化するとき、初期値は新しく作成されたオブジェクトにコピーされます。ただし、参照を定義する場合、プログラムは初期値を参照にコピーするのではなく、参照をその初期値にバインドします。初期化が完了すると、参照は常に初期値オブジェクトにバインドされます。参照を別のオブジェクトに再バインドすることはできないため、参照を初期化する必要があります。
2.変数は複数の参照を持つことができます
3.参照がエンティティに参照されると、他のエンティティは参照できなくなります
int val = 10;
int val_1 = 20;
int &ra = val;
int &ra = val_1;//会报错:因为ra已经与val绑定,再不能引用其他实体。
int &rra = val;//一个实体(变量)可以有多个引用
注:C ++ 11には、いわゆる「右辺値参照」という新しいタイプの参照が追加されました。この種の参照は、主に組み込みクラスに使用されます。厳密に言えば、「参照」という用語を使用するときは、実際には「左辺値参照」を指します。
1.2頻繁に引用される(constへの参照)
基本的な参照では、すべての参照型は、それらにバインドされたオブジェクトと厳密に一致する必要があります(例外を除く)。さらに、参照はオブジェクトにのみバインドでき、リテラル値や式の計算結果にはバインドできません。
const int a = 10;
int &ra = a;//错误:a为常量
const int &ri = a;//正确:引用以及其对应的对象都是常量。
const int a = 10;
int &ra = a;//错误:a为常量
const int &ri = a;//正确:引用以及其对应的对象都是常量。
ri = 42;//错误:ri是对常量的引用
int &rb = a;//错误:试图让一个非常量引用指向一个常量对象。
上記のように、参照されるタイプは、参照するオブジェクトのタイプと一致している必要がありますが、例外があります。最初の例外は、式の結果を参照型に変換できる限り、定数参照を初期化するときに任意の式が初期値として許可されることです。
定数参照が別の型にバインドされたときに何が起こるかを見ることができます。
double d = 12.34;
//int &rd = d;//错误:因为类型不同
const int& rd = d;//为什么就正确了?
ここで、rdはint型の整数を指します。rdの演算は整数演算子である必要がありますが、dは整数ではなく倍精度浮動小数点数です。したがって、rdが整数にバインドされていることを確認するために、コンパイラは上記のコードを次の形式に変換します。
const int temp = d;//由双精度浮点数生成一个临时的整形常量
const int& rd = temp;//让rd绑定这个常量
この場合、rdは一時オブジェクトをバインドします。いわゆる一時オブジェクトは、コンパイラが式の評価結果を一時的に格納するためのスペースを必要とするときに作成される名前のないオブジェクトです。rdでバインドされたオブジェクトは、dではなく一時的なものであることに注意してください。
1.3参照使用シナリオ
1.パラメータを作成します
void Swap(int& left,int& right)
{
int tmp = left;
left = right;
right = tmp;
}
2.戻り値を作成します
int& Count()
{
static int n = 0;
n++;
//.....
return n;
}
Q:次のコードの結果は何ですか?
#include <iostream>
using namespace std;
int& Add (int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1,2);
Add(3,4);
std::cout<<"Add(1,2) = "<<ret<<endl;
return 0;
}
注:関数が関数のスコープ外に戻った場合、返されたオブジェクトがシステムに返されない場合は、参照による戻りを使用でき、参照による戻りを使用できます。システムに返された場合、値による戻りを使用する必要があります。
上記のすべてのプログラムは、関数のライフサイクルが終了した後、スタックフレームをロールバックします。参照が指すアドレスは、必ずしも安全でアクセス可能であるとは限りません。
要約すると、ローカル変数に引用しないでください。
この問題に対応して、次のように書き直した場合:
#include <iostream>
using namespace std;
int& Add (int a,int b)
{
static int c = a + b;
return c;
}
int main()
{
int& ret = Add(1,2);
Add(3,4);
std::cout<<"Add(1,2) = "<<ret<<endl;
return 0;
}
その後、結果にいくつかの変更があります(この予兆、将来のレビューのために保存してください)。
1.4値渡しと参照渡しの効率の比較
値をパラメーターまたは戻り値の型として使用します。パラメーターの受け渡しおよび戻り中に、関数は実際のパラメーターを直接渡したり、変数自体を返したりしません。実際のパラメーターを渡すか、変数の一時コピーを返すことを知っているので、値をパラメーターとして使用します。または戻り値タイプの場合、効率は非常に低くなります。参照は新しいメモリスペースを開かないので、非常に効率的です。
1.5参照とポインタの違い
参照は文法概念の別名です。独立したスペースはなく、参照するオブジェクトと同じメモリスペースを共有します。ただし、トリガーはポインターの方法で実装されるため、参照は実際には基になる実装のスペースによって行われます。
参照とポインターの違い:
1。参照は、定義時に初期化する必要があり、ポインターは必要ありません。
2.初期化中にエンティティを参照した後は、他のエンティティを参照できなくなり、ポインタはいつでも同じタイプの任意のエンティティを指すことができます。
3.参照にはNULL参照がありませんが、NULLポインターがあります。
4.サイズが異なり、参照のサイズはそれ自体の参照タイプのサイズであり、ポインターのサイズは4バイトに固定されています(32ビットプラットフォーム)
5。参照は参照されるエンティティに追加されます、およびポインタがポインタに追加されて後方になります。型のサイズをシフトします。
6.マルチレベルのポインタはありますが、マルチレベルの参照はありません。
7.エンティティにアクセスする方法が異なり、ポインタを逆参照する必要があり、参照はコンパイラ自体によって処理されます。
8.参照は、ポインターよりも比較的安全に使用できます。
2、インライン関数
1.インライン関数とは
インラインで装飾された関数はインライン関数と呼ばれます。コンパイル時に、C ++コンパイラはインライン関数が使用される場所を拡張します。スタックをプッシュする関数のオーバーヘッドはありません。インライン関数は、プログラム操作の効率を向上させることができます。
2.インライン関数の機能
1.インライン関数は、タイムゾーンをスペースごとに変更する方法であり、関数を呼び出すための余分なオーバーヘッドを節約します。したがって、コードが非常に長い、ループしている、または再帰的である場合、インライン関数を使用することは適切ではありません。
2.インライン関数はコンパイラーへの単なる提案であり、コンパイラーは自動的に最適化します。インラインとして定義された関数本体にループまたは再帰がある場合、コンパイラーは最適化時にインライン関数を自動的に無視します。
3.宣言と定義を分離するためにインラインを使用することはお勧めしません。分離するとリンクエラーが発生します。インラインが展開されるため、関数アドレスがなく、リンクが見つかりません。
3、自動キーワード(C ++ 11)
C ++ 11では、標準委員会がautoの新しい定義を提供しました。autoはストレージタイプインジケーターではなく、コンパイラーに指示する新しいタイプインジケーターです。autoによって宣言された変数は、コンパイル時にコンパイラーによって宣言される必要があります。派生。
using namespace std;
int TestFun()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = b;
auto d = TestFun();
return 0;
}
注:autoを使用して変数を定義する場合は、変数を初期化する必要があります。コンパイルフェーズでは、コンパイラーは初期化式に従って実際のタイプのautoをプッシュする必要があります。したがって、autoは「型」宣言ではなく、型宣言の「プレースホルダー」です。コンパイラーは、コンパイル時にautoを実際の変数型に置き換えます。
自動の使用に関する規則
1. Autoは、ポインターおよび参照と組み合わせて使用されます
2.同じ行に複数の変数を定義します
void TestFun()
{
auto a = 1,b = 2;
auto c = 3,d = 4.0;//d = 4.0会出错,因为c和d的表达式类型不同
}
同じ行で複数の変数を宣言する場合、これらの変数は同じ型である必要があります。そうでない場合、コンパイラは実際には最初の型のみを推定し、推定型を使用して他の変数を定義するため、エラーを報告します。
3.オートがプッシュできないシーン
#include <iostream>
using namespace std;
void TestFun(auto a)
{
}
void TestFun(auto a)//编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
{
}
void TestAuto()
{
int a[] = {
1,2,3};
//auto b[] = {4,5,6};//auto不能直接用来声明数组;
auto c = a;//此处c的类型为int*
}