C++11新特性選講 語言部分 侯捷

C++11新特性選講 語言部分 侯捷

本課程分為兩個部分:語言的部分和標準庫的部分。只談特性,并且是講。

本文為語言部分筆記。

  • 語言
    • Variadic Templates
    • move semantics
    • auto
    • Range-based for loop
    • Initializer list
    • Lambdas
  • 標準庫
    • type_traits
    • unodered containers
    • forward_list
    • array
    • tuple
    • concurrency
    • RegEx

關于頭文件

C++11的新特性包含語言和標準庫兩部分,后者以頭文件 header files 的形式呈現。

關于C++的頭文件,有以下幾點:

  • C++標準庫的頭文件均不帶 .h,如 #include <iostream>
  • 在C++中,舊式的C的頭文件(帶有 .h)依然可用,如 #include <stdio.h>
  • 建議在C++中使用,新式的C頭文件,與舊式的關系:xxx.h -> cxxx,如 #include <cstdio>

Variatic Templates

函數變參模板

假如我想設計一個函數 print,它能夠接收任意數量的參數,并且這個參數的類型也是任意的,就可以利用 Variatic Templates 來遞歸地實現:

#include <iostream>
void print() {}				// 1template<typename T, typename... Types>				// 2
void print(const T& firstArg, const Types&... args) {			// 3std::cout << firstArg << std::endl;print(args...);					// 4
}int main() {print("dfafda", 's', 123);
}

注意這里的 ... 可不是我們口語中的省略號,而是實實在在的C++11新語法的一部分,可以將它理解為一個 pack (包),具體是什么 “包”,則取決于它出現在哪里。在本例中,... 共出現了三次:

  • 用于 template parameters,就是 template parameters pack,”模板參數包“,如2處
  • 用于 function parameters types,就是 function parameters types pack,”函數參數類型包“,如3處
  • 用于 function parameters,就是 function parameters pack,“函數參數包”,如4處

在變參模板中,如果我們想要知道可變參數的個數,可通過:sizeof...(args)

注意除了2處, 我們在1處定義了一個空參數列表的 print 函數的重載版本,它在 print 函數地參數列表中的參數被遞歸地打印完之后被調用,其實就是相當于我們 print 函數的遞歸退出的條件。

思考:以下這個 print 函數的重載版本能夠與上面的 print 函數并存嗎,如果可以,誰比較泛化,誰比較特化呢?(我們知道,兩個版本均可的情況下,較為特化的版本會被優先調用)

template <typename... Types>
void print(const Types&... args) {/* --- */
}

變參模板的花式應用

  1. 萬能的hash function:多種函數重載 + 遞歸 + 函數變參模板 —>花式調用

在這里插入圖片描述

  1. tuple:類變參模板 + 繼承

在這里插入圖片描述

類變參模板

一些”小“的新特性

Spaces in Template Expressions

在C++11之前,如果有模板嵌套,右側的兩個尖括號不能靠在一起,中間須有空格,否則編譯器會認為那是個右移運算符,在C++11之后編譯器變聰明了,不再需要這個空格。

vector<list<int> >; 			// OK in each C++ version
vector<list<int>>; 			// OK since C++ 11

nullptr and std::nullptr_t

在C++11之后,我們可以使用 nullptr (而非之前的 NULL 或者 0)來表示空指針。注意 NULL 就是一個宏,其值為0,而 nullptr 確實是個指針,其類型為 std::nullptr_t。下面的例子可以驗證:

#include <iostream>void f(int) {std::cout << "call f(int)" << std::endl;
}void f(void*) {std::cout << "call f(void*)" << std::endl;
}int main() {f(0);					// calls f(int)f(NULL);			// calls f(int) if NULL is 0; ambiguous otherwisef(nullptr);		// calls f(void*)
}

auto

自動類型推導 auto:在C++11之后,可以用 auto 來定義變量的類型,編譯器會自動進行類型推導。

auto i = 42;		// i是int類型
double f();
auto d = f();		//	d是double類型

注意:不建議在任何時候都使用 auto ,而是推薦在這個變量的類型名稱實在是很長或者很復雜,實在是懶得打那么多字時使用,但是我們要知道變量應該是什么類型,如:

vector<string> v;
auto pos = v.begin();			// 過長auto f = [](int x) -> bool {			// 過于復雜// ...
}

程序員要做到對自己的變量類型心中有數

Uniform Initialization

在C++11之前,許多程序員會疑惑,一個變量或者對象的初始化可能會發生于小括號,大括號,賦值運算符。如:

vector<int> vec(3, 5);
vector<int> vec {1, 2 ,3};
int a = 1;

C++11引入一致初始化,使用大括號,在變量后面直接跟大括號,大括號中可以有任意多個元素個數,設置初值,進行初始化,如:

int values[] {1, 2, 3};
vector<int> v {2, 3, 4};
complex<double> {4.0, 3.0};

當然之前的語法也是可用的。

實際上,編譯器看到 {} 就會作出一個 initializer_list<T>,它關聯至一個 array<T, n>。調用函數(如ctor)時該 array 的元素被編譯器分解逐一傳給函數。需要注意的是:若某個函數參數就是個 initializer_list<T>,調用者不能傳遞數個 T 參數然后以為它們會被自動轉換為一個 intializer_list<T> 傳入,即需要自己手動將數個參數轉換為 initializer_list<T> 再進行傳值。

比如:

vector<string> cities {"Berlin", "New York", "London"};

這形成一個 initializer_list<string> ,背后有個 array<string, 3>。調用 vector<string> 的 ctors(構造函數)中的接收 initialize_list<string> 的版本,標準庫中所有容器都有接收這個 initializer_list<T> 的構造函數。

但是對于我們自己的類,可能沒有接收 intializer_list<T> 這種參數的構造函數,此時這個初始化列表逐一分解拆成一個一個的參數傳給函數,再去找與多個單個參數相匹配的構造函數。

initializer_list

初始化列表是支持上面提到的大括號形式的一致性初始化的背后方法。

為了支持用戶自定義的類的 initializer_list。C++11提供了一個類模板:std::initializer_list<T>。他可以用用于使用一包參數值來進行初始化,或者用來其他你想要處理一包參數的地方。如使用initalizer_list傳參:

#include <iostream>void print(std::initializer_list<int> vals) {for (auto ite = vals.begin(); ite!=vals.end(); ++ite) {std::cout << *ite << "\n";}
}int main() {print( {1,2,3,4} );				// 使用initalizer_list傳參
}
  • {} 即可形成一個 initializer_list

  • 不同于前面的 variadic template,這里的 initializer_list 需要的是固定類型 T 的任意多個參數。也可以看做是一種容器。

  • initializer_list背后由array構建。

  • intializer_list如果被拷貝,會是淺拷貝(引用語義)

在C++11之后的標準庫中,initializers_list 有許多應用,最常見的肯定是上面提到過的各個容器的構造函數中可以使用其作為參數。另外,在一些算法中也有應用,比如 min/max 函數,在C++11之前,它們只能支持兩個元素的比較:

std::min(1, 2);

在C++11之后,借助 initializer_list 它可以支持多個元素的比較:

std::min( {1, 2, 3, 4} );

range-based for loop

在C++11之后

for (decl : coll) {statement;
}

如:

std::vector<int> vec = {1, 2, 3, 4};
for (int i : vec) {std::cout << i << std::endl;
}

也可以用引用:

std::vector<double> vec;
for (auto& elem : vec) {elem *= 3;		// 因為是引用,所以會改變原vector
}

類似python的for loop:

for i in range(10):print(i)

實際上,這種for loop的背后實現就是將該容器的迭代器取出來,并遍歷一遍,并將遍歷過程中的每個元素賦值到左側聲明出來的變量。

這種for loop賦值時可能會做隱式類型轉換。

=default, =delete

如果你自行定義了一個 ctor,那么編譯器就不會再給你一個 default ctor;但是如果你強制加上 =default (可以空格),就可以重新獲得并使用默認的 default ctor。而如果加上 =delete,則是禁用該成員函數的使用。

class Zoo {
public:Zoo(int i1, int i2) : d1(i1), d2(i2) {}		// 構造函數Zoo(const Zoo&) = delete;		// 拷貝構造Zoo(Zoo&&) = default;			// 移動構造Zoo& operator=(const Zoo&) = default;		// 拷貝賦值Zoo& operator=(const Zoo&&) = delete;		// 移動賦值virtual ~Zoo() {}				// 析構函數
private:int d1, d2;
}

=default

每當我們聲明一個有參構造函數時,編譯器就不會創建默認構造函數。在這種情況下,我們可以使用 =default 說明符來創建默認的構造函數。以下代碼演示了如何創建:

// use of defaulted functions
#include <iostream>
using namespace std;class A {
public:// A user-definedA(int x){cout << "This is a parameterized constructor";}// Using the default specifier to instruct// the compiler to create the default implementation of the constructor.A() = default;
};int main(){A a;          //call A()A x(1);       //call A(int x)cout<<endl;return 0;
} 

=delete

在C ++ 11之前,操作符delete 只有一個目的,即釋放已動態分配的內存。而C ++ 11標準引入了此操作符的另一種用法,即:禁用成員函數的使用。這是通過附加 = delete 來完成的; 說明符到該函數聲明的結尾。

使用 = delete 說明符禁用其使用的任何成員函數稱為explicitly deleted函數。

雖然不限于它們,但這通常是針對隱式函數。以下示例展示了此功能派上用場的一些任務:

禁用拷貝構造函數

// copy-constructor using delete operator 
#include <iostream> 
using namespace std; class A { 
public: A(int x): m(x) { } // Delete the copy constructor A(const A&) = delete;      // Delete the copy assignment operator A& operator=(const A&) = delete;  int m; 
}; int main() { A a1(1), a2(2), a3(3); // Error, the usage of the copy assignment operator is disabled a1 = a2;   // Error, the usage of the copy constructor is disabled a3 = A(a2);  return 0; 
} 

禁用不需要的類型轉換

// type conversion using delete operator 
#include <iostream> 
using namespace std; 
class A { 
public: A(int) {} // Declare the conversion constructor as a  deleted function. Without this step,  // even though A(double) isn't defined,  the A(int) would accept any double value//  for it's argumentand convert it to an int A(double) = delete;  
}; 
int main() { A A1(1); // Error, conversion from  double to class A is disabled. A A2(100.1);  return 0; 
} 

請注意,刪除的函數是隱式內聯的,這一點非常重要。刪除的函數定義必須是函數的第一個聲明。換句話說,以下方法是將函數聲明為已刪除的正確方法:

class C {
public:C(C& a) = delete;
};

但是以下嘗試聲明刪除函數的方法會產生錯誤:

// incorrect syntax of declaring a member function as deleted 
class C  { 
public: C(); 
}; // Error, the deleted definition of function C must be the first declaration of the function. 
C::C() = delete;  

最后,明確刪除函數有什么好處?

刪除特殊成員函數提供了一種更簡潔的方法來防止編譯器生成我們不想要的特殊成員函數。(如“禁用拷貝構造函數”示例中所示)。

刪除正常成員函數或非成員函數可防止有問題的類型導致調用非預期函數(如“禁用不需要的參數轉換”示例中所示)。

Big Five,指每個類的拷貝控制,即構造函數、拷貝構造函數、移動構造函數、拷貝賦值函數、移動賦值函數、析構函數。它們默認是 public 且 inline 的。

  • =default 不能用于 Big Five 之外的常規函數:編譯會報錯,因為其他函數并沒有默認的版本。
  • =delete 可以用于任何函數身上(但好像沒什么意義,不需要某個函數不寫就是了,為什么要寫了再=delete呢),注意類似的 =0 只能用于虛函數,這樣會使得該虛函數稱為純虛函數,強迫子類重寫該函數。

alias template (template typedef)

帶參數的別名模板。

template <typename T>
using Vec = std::vector<T, MyAlloc<T>>;

注意這里的 using 關鍵字并不是 C++11 的新東西,但是 using 關鍵字的這種使用方法是C++11之后的新的用來做 alias template 的方法。

在經過了上面的定義之后,以下兩種寫法是等價的:

Vec<int> coll;
// 等價于
std::vector<int, MyAlloc<int>> coll;

如此我們可以方便地使用我們自己的分配器 MyAlloc 創建一個類型可選的 vector 對象。

注意,大家注意到這種用法和我們的宏定義和 typedef 好像有些類似,但是實際上使用 macro 宏定義或 typedef 均無法實現上面的效果。

  1. 若使用宏定義:

    #define Vec<T> template<typename T> std::vector<T, MyAlloc<T>>;
    

    我們知道宏定義就是機械地字符替換,所以在使用時:

    Vec<int> coll;
    // 等價于
    template<typename int> std::vector<int, MyAlloc<int>>;
    

    完全不是我們想要的意思。

  2. 若使用 typedef 也不行,因為 typedef 是不接收參數的。

    至多寫成:

    typedef std::vector<int, MyAlloc<int>> Vec;
    

    這當然也不是我們想要的,沒辦法指定變量的類型。

注意 alias template 不能做偏特化或全特化。

type alias (similar to typedef)

using value_type = T;
// 等價于
typedef T value_type;

與上面的 alias template 類似,這里的 using 關鍵字的這種使用方法是C++11之后的新的用來做 type alias 的方法。

using func = void(*)(int, int);
// 等價于
typedef void (*func)(int, int);// 使用func,作為函數指針類
void example(int, int) {}
func fn = example;

后面這個例子中的 func 被定義為一種類型,它是一個函數指針類型。

using關鍵字總結

  1. using-directives,如 using namespace std;

  2. using-declarations for namespace members,如 using std::cout;

  3. using-declarations for class members,如 using _Base::_M_allocate;

  4. type alias (since C++11),如:

    template <typename T>
    using Vec = std::vector<T, MyAlloc<T>>;
    
  5. alias template (since C++11),如 using func = void(*)(int, int);

noexcept

void foo() noexcept {// ...
}

程序員保證 foo() 函數不會拋出異常,讓別人/編譯器“放心地”調用該函數。

實際上 noexcept 關鍵字還可以加參數,來表示在…條件下,函數不會拋出異常,上面的 void foo() noexcept ; 就等價于 void foo() noexcept(true);, 即相當于無條件保證。

而下面:

void swap(Type& x, Type& y) noexcept(noexcept(x.swap(y))) {x.swap(y);
}

則意為在 x.swap(y) 不拋出異常的條件下,本函數不會拋出異常。

補充一下,異常是這樣的,如果 A 調用 B,B 調用 C,而在 C 執行的過程中出現了異常,則先看 C 有沒有寫明異常處理程序,如果有,則處理;如果沒有,則異常傳遞給 B,然后看 B 有沒有對應的異常處理程序,如果有,則處理;如果也沒有,則繼續傳遞給 A。即按照調用順序一層一層地向上傳遞,直到有對應的異常處理程序。如果用戶一直沒有異常處理程序,則執行 std::terminate() ,進而執行 std::abort() ,程序退出。

override

override 關鍵字,標明重寫,應用于虛函數身上。

考慮下面這種情況:

struct Base {virtual void vfunc(float) { }
};struct Derived: Base {// virtual void vfunc(int) { }virtual void vfunc(int)	override { }
}

子類 Derived 在繼承父類 Base 之后想要重寫父類的 void vfunc(float) 方法,但是我們知道,要重寫父類方法需要函數簽名完全一致,這里可能由于疏忽大意,將參數類型寫為了 int。這就導致子類的這個函數定義了一個新函數,而非是期望中的對于父類函數的重寫了。而編譯器肯定是不知道你其實是想重寫父類方法的,因為你函數簽名的不一致,就按照一個新方法來處理了。

在 C++11 之后,引入了 override 關鍵字,在你確實想要重寫的函數之后,加上這個關鍵字,編譯器會在你在想重寫但是函數簽名寫錯的時候提醒你,這個被標記為重寫函數的函數實際上并未進行重寫。

final

  1. 修飾類,使得該類不能被繼承

    struct Base final {};struct Derived: Base {};			// Error
    

    Base 類被 final 關鍵字修飾,使得其不能被繼承,下面的 Derived 試圖繼承它,會報錯。

  2. 修飾虛函數,使得該虛函數不能被重寫

    struct Base {virtual void func() final;
    }struct Derived : Base {void func();			// Error
    }
    

    Base 類本身沒有被 final 修飾,所以可以被繼承。但是其虛函數 func()final 關鍵字修飾,故 func() 不能被重寫。下面的 Derive 類試圖重寫它,會報錯。

decltype

獲取一個變量/一個對象的類型 (即 tpyeof(a) )是非常常見的需求,但是在 C++11 之前并沒有直接提供這樣的關鍵字(僅有 typeid 等)。 decltype 可以滿足這一需求,方便地獲得變量 / 對象的類型。

decltype 用來定義一種類型,該類型等同于一個類型表達式的結果。如 decltype(x+y) 定義了 x+y 這個表達式的返回類型。

map<string, float> coll;
decltype(coll)::value_type elem;

在C++11之前只能:

map<string, float>::value_type elem;

這當然不能讓我們在未知變量 / 對象的類型的條件下知道其類型。

decltype 的三種應用場景:

1-用來聲明返回值類型

有時候,函數返回值的類型取決于參數的表達式的執行結果。然而,在C++11之前,沒有 decltype 之前,以下語句是不可能成立的:

template<typename T1, typename T2>
decltype(x+y) add(T1 x, T2 y);

因為上面的返回值的類型使用了尚未引入且不再作用域內的對象。

但是在C++11之后,我們可以通過在函數的參數列表之后聲明一個返回值類型來實現:

template<typename T1, typename T2>
auto add(T1 x, T2 y) -> decltype(x+y);

這與 lambda 表達式聲明返回值的語法相同:
[...](...)mutableoptthrowSpecopt?>retTypeopt{...}[...](...)\ mutable_{opt}\ throwSpec_{opt}->retType_{opt}\{...\} [...](...)?mutableopt??throwSpecopt??>retTypeopt?{...}
2-元編程

元編程是對模板編程的運用。

舉例:

typdef typename decltype(obj)::iterator iType;
// 類似 typedef typename T::iterator iType;
decltype(obj) anotherObj(obj);

3-傳遞lambda的類型

面對lambda,我們手上往往只有對象,沒有類型,要獲得其類型就得借助于 decltype

如:

auto cmp = [] (const Person& p1, const Person &p2) {return /* 給出Person類比大小的準則 */
}//...
std::set<Person, decltype(cmp)> coll<cmp>;

我們知道由于 set 是有序容器,所以在將自定義的類構成一個 set 的時候需要給出該類比大小的準則(謂詞),通常是函數、仿函數或者 lambda 表達式。但是這里我們同樣需要指定類型,這就可以用 decltype 來指定。

lambdas

C++11 引入了 lambdas ,允許定義一個單行的函數,可以用作是參數或者局部對象。Lambdas 的引入改變了C++標準庫的使用方式(比如原來的一些仿函數謂詞,現在可直接用)。

基本用法

最簡單的 lambda 函數不接收參數,并做一些簡單的事情,比如這里的打印一句話:

[] { std::cout << "Hello Lambda" << std::endl; }

我們可以直接調用它,就像調用普通函數和函數對象那樣,用 ()

[] { std::cout << "Hello Lambda" << std::endl; }();

雖然可以這樣直接低啊用,但是這樣其實沒什么意義,因為你想要打印直接打印就好了,沒必要再繞個圈子,我們通常將 lambda 函數賦值給一個變量,這樣就能像調用普通函數那樣多次調用它:

auto l = [] { std::cout << "Hello Lambda" << std::endl; };
l();
l();
l();

這里 lambda 對象的類型很復雜,通常也沒有必要顯式地寫出來,我們正好用前面介紹過的 C++11 中的 auto 來簡化我們的代碼。如果一定要拿到 lambda 函數對象的類型,參考上面的 decltype 的用法三。

完整形式

lambda 表達式的完整形式:
[...](...)mutableoptthrowSpecopt?>retTypeopt{...}[...]\ (...)\ mutable_{opt}\ throwSpec_{opt}->retType_{opt}\{...\} [...]?(...)?mutableopt??throwSpecopt??>retTypeopt?{...}

  • lambda 函數除了少數幾處細節(如沒有默認構造函數、需要加mutable),幾乎完全等同于一個對應的函數對象
  • [] 稱為 lambda introducer ,其中存放要捕獲的外部變量表,外部變量要注意區分值傳遞和引用傳遞。如果里面放一個等號:[=, &y] 表示接收以值傳遞的形式接收所有的外界變量,不太建議用,要把自己用到的變量寫清楚。
  • () 中存放 lambda 函數的參數列表
  • {} 是 lambda 函數的函數體
  • 中間的三項(標明 opt 的)都是看情況可有可無的,但是一旦三個中有一個是出現的,那么小括號 () 就必須有;而若三個可選項都沒有,則 () 也是可有可無的。
  • mutable 指明參數是否可被改變,throwSpec 指明是否可能會拋出異常,retType 指明返回值的類型
  • lambda 函數默認是內聯的

舉例:

#include <iostream>int main() {int id = 0;auto f = [id] () mutable {std::cout << "id: " << id << std::endl;++id;};id = 42;f();f();f();std::cout << id << std::endl;
}

輸出:

id: 0
id: 1
id: 2
42

注意:

  1. 在定義 lambda 函數 f() 時,就已經把 id 以值傳遞的形式傳給函數,因此后面 id 的改變不會影響函數真正被調用時的 id 值
  2. 不加 mutable 關鍵字會報 id 是只讀變量,不能修改。

varidic template 變參模板詳解

原視頻這里花了很大篇幅來講解變參模板及其應用這個極其重要的新特性,但是考慮到在新手日常編程中的使用并不是太多(而多是出現在大型模板庫的設計中),這里暫時略過,以后再回來補。

Ref:

https://blog.csdn.net/weixin_38339025/article/details/89161324

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532550.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532550.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532550.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java安全(二):JDBC|sql注入|預編譯

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1 JDBC基礎 JDBC(Java Database Connectivity)是Java提供對數據庫進行連接、操作的標準API。Java自身并不會去實現對數據庫的連接、查詢、更新等操作而是通…

java安全(三)RMI

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1.RMI 是什么 RMI(Remote Method Invocation)即Java遠程方法調用&#xff0c;RMI用于構建分布式應用程序&#xff0c;RMI實現了Java程序之間跨JVM的遠程通信…

LeetCode-726 原子的數量 遞歸

LeetCode-726 原子的數量 遞歸 題目鏈接&#xff1a;LeetCode-726 原子的數量 給你一個字符串化學式 formula &#xff0c;返回 每種原子的數量 。 原子總是以一個大寫字母開始&#xff0c;接著跟隨 0 個或任意個小寫字母&#xff0c;表示原子的名字。 如果數量大于 1&#xf…

java安全(四) JNDI

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1.JNDI JNDI(Java Naming and Directory Interface)是Java提供的Java 命名和目錄接口。通過調用JNDI的API應用程序可以定位資源和其他程序對象。JNDI是Java…

二叉樹的層序遍歷和前中后序遍歷代碼 迭代/遞歸

前中后序遍歷&#xff08;DFS&#xff09; 首先我們要明確前中后序遍歷的順序&#xff1a; 前序&#xff1a;中左右中序&#xff1a;左中右后序&#xff1a;左右中 前中后序遍歷的遞歸代碼和迭代代碼分別有各自的框架&#xff0c;然后根據遍歷順序調整記錄元素的位置即可。 …

java安全(五)java反序列化

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1. 序列化 在調用RMI時,發現接收發送數據都是反序列化數據. 例如JSON和XML等語言,在網絡上傳遞信息,都會用到一些格式化數據,大多數處理方法中&#xff0c…

git merge和rebase的區別與選擇

git merge和rebase的區別與選擇 轉自&#xff1a;https://github.com/geeeeeeeeek/git-recipes/wiki/5.1-%E4%BB%A3%E7%A0%81%E5%90%88%E5%B9%B6%EF%BC%9AMerge%E3%80%81Rebase-%E7%9A%84%E9%80%89%E6%8B%A9#merge BY 童仲毅&#xff08;geeeeeeeeekgithub&#xff09; 這是一篇…

java安全(六)java反序列化2,ysoserial調試

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; ysoserial 下載地址&#xff1a;https://github.com/angelwhu/ysoserial ysoserial可以讓?戶根據??選擇的利?鏈&#xff0c;?成反序列化利?數據&…

C++面試常見問題一

C面試常見問題一 轉自&#xff1a;https://oldpan.me/archives/c-interview-answer-1 原作者&#xff1a;[oldpan][https://oldpan.me/] 前言 這里收集市面上所有的關于算法和開發崗最容易遇到的關于C方面的問題&#xff0c;問題信息來自互聯網以及牛客網的C面試題目匯總。答題…

java安全(七) 反序列化3 CC利用鏈 TransformedMap版

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 目錄圖解代碼demo涉及的接口與類&#xff1a;TransformedMapTransformerConstantTransformerInvokerTransformerChainedTransformerdome理解總結&#xff1a…

C++編譯時多態和運行時多態

C編譯時多態和運行時多態 作者&#xff1a;melonstreet 出處&#xff1a;https://www.cnblogs.com/QG-whz/p/5132745.html 本文版權歸作者和博客園共有&#xff0c;歡迎轉載&#xff0c;但未經作者同意必須保留此段聲明&#xff0c;且在文章頁面明顯位置給出原文連接&#xff0…

java安全(八)TransformedMap構造POC

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 上一篇構造了一個了commons-collections的demo 【傳送門】 package test.org.vulhub.Ser;import org.apache.commons.collections.Transformer; import org…

Pytorch Tutorial 使用torch.autograd進行自動微分

Pytorch Tutorial 使用torch.autograd進行自動微分 本文翻譯自 PyTorch 官網教程。 原文&#xff1a;https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html#optional-reading-tensor-gradients-and-jacobian-products 在訓練神經網絡時&#xff0c;最常使用…

TVM:編譯深度學習模型快速上手教程

TVM&#xff1a;編譯深度學習模型快速上手教程 本文將展示如何使用 Relay python 前端構建一個神經網絡&#xff0c;并使用 TVM 為 Nvidia GPU 生成一個運行時庫。 注意我們需要再構建 TVM 時啟用了 cuda 和 llvm。 TVM支持的硬件后端總覽 在本教程中&#xff0c;我們使用 cu…

TVM:設計與架構

TVM&#xff1a;設計與架構 本文檔適用于想要了解 TVM 架構和/或積極開發項目的開發人員。頁面組織如下&#xff1a; 示例編譯流程概述了 TVM 將模型的高層描述轉換為可部署模塊所采取的步驟。要開始使用&#xff0c;請先閱讀本節。 邏輯架構組件部分描述了邏輯組件。后面的部…

遞歸+回溯

遞歸-回溯 本文參考自代碼隨想錄視頻&#xff1a; https://www.bilibili.com/video/BV1cy4y167mM https://www.bilibili.com/video/BV1ti4y1L7cv 遞歸回溯理論基礎 只要有遞歸&#xff0c;就會有回溯&#xff0c;遞歸函數的下面的部分通常就是回溯的邏輯。 回溯是純暴力的搜索…

Nvidia CUDA初級教程1 CPU體系架構綜述

Nvidia CUDA初級教程1 CPU體系架構綜述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p2 講師&#xff1a;周斌 本節內容&#xff1a;了解現代CPU的架構和性能優化&#xff1a; 流水線 Pipelining分支預測 Branch Prediction超標量 Superscalar亂序執行 Out…

Nvidia CUDA初級教程2 并行程序設計概述

Nvidia CUDA初級教程2 并行程序設計概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p3 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要&#xff1f;怎么做&#xff1f;一些技術和概念 串并行計算模式 串行計算模式 常規軟件時串行的 設計運行…

Nvidia CUDA初級教程4 GPU體系架構概述

Nvidia CUDA初級教程4 GPU體系架構概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p5 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要GPU三種方法提升GPU的處理速度實際GPU的設計舉例&#xff1a; NVDIA GTX 480: FermiNVDIA GTX 680: Kepler GP…

Nvidia CUDA初級教程5 CUDA/GPU編程模型

Nvidia CUDA初級教程5 CUDA/GPU編程模型 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p6 講師&#xff1a;周斌 本節內容&#xff1a; CPU和GPU互動模式GPU線程組織模型&#xff08;需要不停強化&#xff09;GPU存儲模型基本的編程問題 CPU與GPU交互 各自…