中国大学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を完全にサポートします.
統合された初期化方法
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;
}