中国大学MOOCプログラム設計とアルゴリズム(三):C++対象向けプログラム設計第十週C++11新特性とC++高級テーマノートのC++11新特性(一)
52081 ワード
第10週C++11新特性とC++高級テーマ1.C++11の新しい特性(一)2.C++11の新しい特性(二)3.強制型変換4.例外処理
1.C++11の新しい特性(一)C++2011年の新しい標準、gcc 4.8コンパイラはC++11を完全にサポートします.
統合された初期化方法
メンバー変数のデフォルト初期値
autoキーワード
変数を定義するために用いられ,自動的に変数を判断できるタイプをコンパイルし,autoを用いる場合は初期化が必要であることを意味する.
decltypeキーワード
式のタイプを返す
スマートポインタshared_ptr、まだ役に立ちます
ヘッダファイル:クラステンプレートでshared_を介してptrの構造関数はshared_ptrオブジェクトは、new演算子が返すポインタを管理します.書き方は次のとおりです.
その後ptrはT*タイプのポインタのように使用できます.すなわち、*ptrはnewで動的に割り当てられたオブジェクトであり、メモリを解放する心配はありません.newから出てきたものは、すべての管理されているスマートポインタが管理を放棄すると、自動的に解放され、newがオブジェクトであれば、構造関数を実行します.複数shared_ptrオブジェクトはポインタを同時に管理でき、システムは管理カウントを維持します.shared_がない場合ptrがポインタを管理する場合、deleteはポインタを管理します.sp1.get()メンバー関数は、スマートポインタが管理するポインタを除去します.A * p = sp1.get();//pはsp 1が管理するポインタsp 1を指す.reset()メンバー関数は、スマートポインタが管理するポインタを放棄します.sp1.reset(q)メンバー関数は、スマートポインタがポインタqを管理し始める.shared_ptrオブジェクトは、動的に割り当てられた配列へのポインタを管理できません.そうしないと、プログラムの実行にエラーが発生します.
空のポインタnullptr、NULLに似ています
範囲ベースforサイクル
牛逼啊,高大上!!!神器を装う
右の値の引用とmoveの意味、とても面白いです
右の値:一般的に、アドレスを取ることができない式は、右の値で、アドレスを取ることができるのは、左の値です.
通常&は左値参照、&&は右値参照であり、一時変数などの右値を参照できます.主な目的は,プログラムの実行効率を向上させ,深いコピーを必要とするオブジェクトの深いコピー回数を減らすことである.深いコピーを意識的に避ける.
例:自分で書いたstringクラス
move()式:右に変換
関数の戻り値がオブジェクトの場合、戻り値オブジェクトはどのように初期化されますか?
ライトコピーコンストラクタライトコピーコンストラクタ:returnローカルオブジェクト->returnグローバルオブジェクトのコピー->ライト移動コンストラクタのコピー:returnローカルオブジェクト->returnグローバルオブジェクトの移動->デフォルトコピーreturn move(グローバル対向)->同時ライトコピーコンストラクタと移動コンストラクタの移動:returnローカルオブジェクト->returnグローバルオブジェクトの移動->return moveのコピー(グローバル対向)-〉dev c++を移動すると、returnローカルオブジェクトが最適化され、構造関数の移動またはコピーが呼び出されません.
移動可能でコピー不可のオブジェクト:
1.C++11の新しい特性(一)C++2011年の新しい標準、gcc 4.8コンパイラはC++11を完全にサポートします.
統合された初期化方法
int arr[3]{1, 2, 3};
vector<int> iv{1, 2, 3};
map<int, string> mp{{1, "a"}, {2, "b"}};
string str{"Hello World"};
int * p = new int[20]{1,2,3};
struct A {
int i,j;
A(int m,int n):i(m),j(n) { }
};
A func(int m,int n ) { return {m,n}; }
int main() { A * pa = new A {3,7}; }
メンバー変数のデフォルト初期値
class B
{
public:
int m = 1234;
int n;
};
int main()
{
B b;
cout << b.m << endl; // 1234
return 0;
}
autoキーワード
変数を定義するために用いられ,自動的に変数を判断できるタイプをコンパイルし,autoを用いる場合は初期化が必要であることを意味する.
auto i = 100; // i int
auto p = new A(); // p A *
auto k = 34343LL; // k long long
map<string,int,greater<string> > mp;
for( auto i = mp.begin(); i != mp.end(); ++i)
cout << i->first << "," << i->second ;
//i : map >::iterator
class A { };
A operator + ( int n,const A & a)
{
return a;
}
template <class T1, class T2>
auto add(T1 x, T2 y) -> decltype(x + y) {//-> decltype(x + y) x+y
return x+y;
}
auto d = add(100,1.5); // d double d=101.5
auto d = add(100,A()); // d A
decltypeキーワード
式のタイプを返す
int i;
double t;
struct A { double x; };
const A* a = new A();
decltype(a) x1; // x1 is A *
decltype(i) x2; // x2 is int
decltype(a->x) x3; // x3 is double
decltype((a->x)) x4 = t; // x4 is double&
スマートポインタshared_ptr、まだ役に立ちます
ヘッダファイル:クラステンプレートでshared_を介してptrの構造関数はshared_ptrオブジェクトは、new演算子が返すポインタを管理します.書き方は次のとおりです.
shared_ptr<T> ptr(new T); // T int ,char,
その後ptrはT*タイプのポインタのように使用できます.すなわち、*ptrはnewで動的に割り当てられたオブジェクトであり、メモリを解放する心配はありません.newから出てきたものは、すべての管理されているスマートポインタが管理を放棄すると、自動的に解放され、newがオブジェクトであれば、構造関数を実行します.複数shared_ptrオブジェクトはポインタを同時に管理でき、システムは管理カウントを維持します.shared_がない場合ptrがポインタを管理する場合、deleteはポインタを管理します.sp1.get()メンバー関数は、スマートポインタが管理するポインタを除去します.A * p = sp1.get();//pはsp 1が管理するポインタsp 1を指す.reset()メンバー関数は、スマートポインタが管理するポインタを放棄します.sp1.reset(q)メンバー関数は、スマートポインタがポインタqを管理し始める.shared_ptrオブジェクトは、動的に割り当てられた配列へのポインタを管理できません.そうしないと、プログラムの実行にエラーが発生します.
#include
#include
using namespace std;
struct A {
int n;
A(int v = 0):n(v){ }
~A() { cout << n << " destructor" << endl; }
};
int main()
{
shared_ptr<A> sp1(new A(2)); //sp1 A(2)
shared_ptr<A> sp2(sp1); //sp2 A(2),
cout << "1)" << sp1->n << "," << sp2->n << endl;
// 1)2,2
shared_ptr<A> sp3;
A * p = sp1.get(); //p A(2)
cout << "2)" << p->n << endl;
sp3 = sp1; //sp3 A(2)
cout << "3)" << (*sp3).n << endl; // 2
sp1.reset(); //sp1 A(2)
if( !sp1 )//sp1
cout << "4)sp1 is null" << endl; //
A * q = new A(3);
sp1.reset(q); // sp1 q
cout << "5)" << sp1->n << endl; // 3
shared_ptr<A> sp4(sp1); //sp4 A(3)
shared_ptr<A> sp5;
//sp5.reset(q);// , , ?
sp1.reset(); //sp1 A(3), , ,
cout << "before end main" <<endl;
sp4.reset(); //sp1 A(3), ,
cout << "end main" << endl;
return 0; // , delete A(2),
}
:
1)2,2
2)2
3)2
4)sp1 is
null
5)3
before end
main
3
destructor
#include
#include
using namespace std;
struct A{
~A() { cout << "~A" << endl; }
};
int main()
{
A * p = new A();
shared_ptr<A> ptr(p);
shared_ptr<A> ptr2;
ptr2.reset(p); // p, ptr2 p, ptr p , ?
cout << "end" << endl;
return 0;
}
:
end
~A
~A
, p delete
空のポインタnullptr、NULLに似ています
#include
#include
using namespace std;
int main() {
int* p1 = NULL;
int* p2 = nullptr;
shared_ptr<double> p3 = nullptr;
if(p1 == p2)
cout << "equal 1" <<endl;
if( p3 == nullptr)
cout << "equal 2" <<endl;
//if( p3 == p2) ; // error,
if( p3 == NULL)
cout << "equal 4" <<endl;
bool b = nullptr; // b = false,nullptr false
int i = nullptr; //error,nullptr
return 0;
}
:
equal 1
equal 2
equal 4
範囲ベースforサイクル
牛逼啊,高大上!!!神器を装う
#include
#include
using namespace std;
struct A {
int n;
A(int i):n(i) { }
};
int main() {
int ary[] = {1,2,3,4,5};
for(int & e: ary)
e*= 10;
for(int e : ary)
cout << e << ",";
cout << endl;
vector<A> st(ary,ary+5);
for( auto & it: st)
it.n *= 10;
for( A it: st)
cout << it.n << ",";
return 0;
}
:
10,20,30,40,50,
100,200,300,400,500,
右の値の引用とmoveの意味、とても面白いです
右の値:一般的に、アドレスを取ることができない式は、右の値で、アドレスを取ることができるのは、左の値です.
class A { };
A & r = A(); // error , A() , ,
A && r = A(); //ok, r
通常&は左値参照、&&は右値参照であり、一時変数などの右値を参照できます.主な目的は,プログラムの実行効率を向上させ,深いコピーを必要とするオブジェクトの深いコピー回数を減らすことである.深いコピーを意識的に避ける.
例:自分で書いたstringクラス
#include
#include
#include
using namespace std;
class String
{
public:
char * str;
String():str(new char[1]) { str[0] = 0;}//
String(const char * s) {//
str = new char[strlen(s)+1];
strcpy(str,s);
}
String(const String & s) {//
cout << "copy constructor called" << endl;
str = new char[strlen(s.str)+1];
strcpy(str,s.str);
}
String & operator=(const String & s) {// ,
cout << "copy operator= called" << endl;
if( str != s.str) {
delete [] str;
str = new char[strlen(s.str)+1];
strcpy(str,s.str);
}
return * this;
}
//
String(String && s):str(s.str) {// ,
cout << "move constructor called"<<endl;
s.str = new char[1];// str , ,
s.str[0] = 0;
}
// ,
String & operator = (String &&s) {
cout << "move operator= called"<<endl;
if (str!= s.str) {
delete [] str;
str = s.str;
s.str = new char[1];
s.str[0] = 0;
}
return *this;
}
~String() { delete [] str; }//
};
template <class T>
void MoveSwap(T& a, T& b) {// a,b , a,b
T tmp(move(a)); // a ,std::move(a) ,
a = move(b); // move(b) ,
b = move(tmp); // move(tmp) ,
}
int main()
{
//String & r = String("this"); // error
String s;
s = String("ok"); // String("ok") ,
cout << "******" << endl;
String && r = String("this");
cout << r.str << endl;
String s1 = "hello",s2 = "world";
MoveSwap(s1,s2);
cout << s2.str << endl;
return 0;
}
:
move operator= called
******
this
move constructor called
move operator= called
move operator= called
hello
move()式:右に変換
関数の戻り値がオブジェクトの場合、戻り値オブジェクトはどのように初期化されますか?
ライトコピーコンストラクタライトコピーコンストラクタ:returnローカルオブジェクト->returnグローバルオブジェクトのコピー->ライト移動コンストラクタのコピー:returnローカルオブジェクト->returnグローバルオブジェクトの移動->デフォルトコピーreturn move(グローバル対向)->同時ライトコピーコンストラクタと移動コンストラクタの移動:returnローカルオブジェクト->returnグローバルオブジェクトの移動->return moveのコピー(グローバル対向)-〉dev c++を移動すると、returnローカルオブジェクトが最適化され、構造関数の移動またはコピーが呼び出されません.
移動可能でコピー不可のオブジェクト:
struct A{
A(const A & a) = delete;
A(const A && a) { cout << "move" << endl; }
A() { };
};
A b;
A func() {
A a;
return a;
}
void func2(A a) { }
int main() {
A a1;
A a2(a1); //compile error
func2(a1); //compile error
func();
return 0;
}