CppCon 2017 學習:10 Core Guidelines You Need to Start Using Now

C.45: 不要定義一個僅僅初始化成員變量的默認構造函數,而是使用類內成員初始化器

如果你有一個默認構造函數,它的唯一作用是給成員變量賦默認值(如 1、2、3),這更清晰、簡單的方法是直接在成員變量聲明時使用類內初始化器(in-class initializers)

C.48: 優先使用類內初始化器,而不是在構造函數中初始化常量初值

解釋:

當初始值是固定的(比如總是初始化為 1、2、3),直接放在成員定義里更清楚、更少重復。

? 重構你的代碼

class Simple {
public:Simple() = default;Simple(int aa, int bb, int cc = -1) : a(aa), b(bb), c(cc) {}Simple(int aa) {a = aa;b = 0;c = 0;}
private:int a{1};int b{2};int c{3};
};

優點:

  • a{1}b{2}c{3} 讓默認初值更直觀。
  • 默認構造函數 Simple() = default; 是自動生成的,不用你寫。
  • 更少代碼,更清晰意圖。

原代碼問題:

Simple() : a(1), b(2), c(3) {}

這只是在做初始化,跟寫在類內沒區別,應該刪掉改為類內初始化器

總結一句話:

如果成員有固定初始值,不要在構造函數里寫,直接在類內初始化。構造函數就用來處理變化的參數。這樣代碼更清晰、更易維護。

你提供的這兩段代碼展示了**使用類內成員初始化器(in-class initializers)**的好處,結合后面列出的 Benefits(好處),我們來逐條解釋。

示例代碼含義解析

class Simple {
public:Simple()  {}  // 用戶定義的默認構造函數Simple(int aa, int bb, int cc) : a(aa), b(bb), c(cc) {}Simple(int aa) : a(aa) {}
private:int a = -1;int b = -1;int c = -1;
};
class Simple {
public:Simple() = default;  // 編譯器自動生成默認構造函數Simple(int aa, int bb, int cc) : a(aa), b(bb), c(cc) {}Simple(int aa) : a(aa) {}
private:int a = -1;int b = -1;int c = -1;
};

在這兩個版本中:

  • 類內初始值 int a = -1; 是默認值,會被任何沒特別賦值的構造函數所使用。
  • 第二個版本通過 = default,使默認構造函數由編譯器自動生成,而不是手寫空函數體。

優點(Benefits)詳解

No arguing about “equivalent” ways to do it

不再爭論各種“等價”的初始化寫法。

統一使用類內初始化器可以避免這樣的問題:

Simple() : a(-1), b(-1), c(-1) {}   // 和
int a = -1; int b = -1; int c = -1; // 哪個更好?

→ 統一方式更清晰,減少團隊代碼風格爭議。

May prevent some bugs

可以防止某些初始化遺漏的 bug。

比如:

Simple(int aa) : a(aa) {}  // 如果 b 和 c 沒在構造函數中初始化

→ 它們就會用類內初始值 -1,不會變成未定義值或垃圾值。

May put you back in “compiler generates constructors” land

有可能讓你回到“讓編譯器自動生成構造函數”的美好世界。

你就可以用 = default 自動生成默認構造函數,不必手寫:

Simple() = default;

→ 更少代碼,更少出錯。

Potentially marginally faster in some circumstances

在某些情況下,這種做法可能更快(邊際提升)。

尤其在使用 std::vector<Simple> 等容器時,類內初始化器有時能讓構造路徑更優化,因為編譯器可能內聯或避免重復初始化。

總結一句話:

類內初始化器 + 默認構造函數 = 更簡單、更安全、更一致的 C++ 代碼。

這符合現代 C++(C++11 起)的最佳實踐,尤其在構造函數中不重復寫相同的默認值。

你提供的是 C++ 核心準則中的一條重要建議:

F.51:如果可以選擇,優先使用默認參數而不是函數重載

示例比較

使用重載實現默認行為(冗余):

class Reactor {
public:double Offset(double a, double b, double ff);double Offset(double a, double b);  // 重載一份只是為了給 ff 默認值
};
double Reactor::Offset(double a, double b, double ff) {// 復雜計算return whatever;
}
double Reactor::Offset(double a, double b) {return Offset(a, b, 1.0);  // 手動添加默認值
}

使用默認參數(簡潔):

class Reactor {
public:double Offset(double a, double b, double ff = 1.0);
};
double Reactor::Offset(double a, double b, double ff /* = 1.0*/) {// 復雜計算return whatever;
}

為什么默認參數更好?(Benefits)

No arguing about “equivalent” ways to do it

避免對兩種“看似等效”的實現方式的爭論。

不用再爭論是要重載兩個版本,還是默認參數好——直接默認參數就行。

Will not forget to make same change to both copies

修改參數邏輯時,不會忘記同步另一個版本。

例如改成使用 ff = 0.95,只要改一處:

double Offset(double a, double b, double ff = 0.95);

→ 避免因為忘改重載函數導致不一致或 bug。

Difference between the two “versions” is crystal clear

不再出現“兩個版本”之間的模糊區別,調用者一目了然。

Offset(10, 20);         // 用默認 ff = 1.0
Offset(10, 20, 0.75);   // 顯式給出 ff

相比重載版本:

Offset(10, 20);         // 哪個版本?(看簽名)
Offset(10, 20, 0.75);   // 不明顯差異

總結一句話:

用默認參數,寫得更少,錯得更少,讀得更清楚

這體現了現代 C++ 的風格傾向:減少重復代碼,提升可維護性與表達力

C.47:定義和初始化成員變量時,應按照它們在類中聲明的順序

為什么這很重要?

在 C++ 中,即使你在構造函數的初始化列表中按照你喜歡的順序寫初始化語句,編譯器實際上仍然會按成員在類中聲明的順序來初始化

示例:存在隱患的代碼

class Wrinkle {
public:Wrinkle(int i) : a(++i), b(++i), x(++i) {}
private:int a;int x;int b;
};

初始化順序實際上是:a → x → b
但你寫的是:a → b → x
這樣會導致:

  • 成員變量 b 被初始化時,依賴了 i 的值(可能和你想的不一樣)
  • 代碼看起來正確,但行為會出錯或讓人困惑
  • 編譯器可能發出警告:“warning: field ‘x’ will be initialized after field ‘b’”

更清晰的正確寫法

class Wrinkle {
public:Wrinkle(int i) : a(++i), x(++i), b(++i) {}
private:int a;int x;int b;
};

更真實的例子

假設:

class Person {
public:Person(string first, string last) : firstName(first), lastName(last), fullName(first + " " + last) {}
private:string firstName;string lastName;string fullName;
};

fullName 依賴于 firstNamelastName但必須確保它在它們后面聲明,否則會使用未初始化的值!

誰可能打亂順序?

  • **“熱心的新人”**試圖按字母順序排列變量
  • 工具可能自動整理字段
  • 有人想按“邏輯分組”整理變量,卻不看構造函數順序

建議(總結)

  • 始終按類中聲明的順序編寫構造函數初始化列表
  • 不要依賴初始化順序之外的副作用(比如 ++i
  • 如果成員間存在初始化依賴,應在聲明順序上表達清晰的意圖

好處

  • 避免初始化順序 bug
  • 不需要每個開發者都記住 C++ 的這個“怪癖”
  • 鼓勵你重新思考類的設計,減少成員之間的耦合依賴

一句話總結:

在初始化列表中改變順序沒用 —— 編譯器會按聲明順序來初始化。為了安全和可讀性,讓你的初始化列表和成員聲明保持一致的順序。

你提到的內容是 C++ 核心準則中的一條設計建議:

I.23: Keep the number of function arguments low

I.23:盡量減少函數參數數量

舉例說明:

糟糕的設計(太多參數):
int area(int x1, int y1, int x2, int y2);
int a = area(1, 1, 11, 21);
  • 參數太多,難記憶,容易出錯。
  • 沒有抽象,含義不清晰(哪個是左上角?哪個是右下角?)。
更好的設計(引入抽象):
int area(Point p1, Point p2);
int a = area({1, 1}, {11, 21});
  • 使用 Point 類型,更清晰地表達意圖。
  • 減少調用者負擔,不需要記位置。
  • 抽象可復用。

進一步示例:構造 Customer

糟糕設計:
Customer(string pfirst, string plast, string pph,string sfirst, string slast, string sph, string sid);
  • 多達 7 個字符串參數,難維護。
  • 非常容易傳錯。
改進設計:
class Customer {Person details;Salesrep rep;
public:Customer(Person p, Salesrep s);
};
  • 將數據封裝進合適的結構(如 Person, Salesrep)。
  • 調用清晰,代碼更易維護。

核心好處

優點說明
更低的認知負擔用戶不用記住那么多參數順序
更清晰的意圖表達結構化參數讓含義更明確
抽象可以復用Point, Person 可以在別處使用
降低未來代碼變更影響只需改結構體,函數簽名不動

小結一句話:

函數參數越少越好,如果超過 3-4 個,應該考慮把它們組合進結構體或類里。

ES.50: Don’t cast away const

不要去除 const 限定符(不要“cast away const”)

背景問題

我們有一個 Stuff 類,其中包含一個緩存機制 cachedValue,希望在 getValue() 中使用它。
getValue()const 函數,不能修改任何成員變量。

錯誤做法:
int Stuff::getValue() const {if (!cacheValid) {cachedValue = LongComplicatedCalculation();  //  編譯錯誤,修改了成員cacheValid = true;}return cachedValue;
}

如果你想讓它編譯,有人可能會寫:

int Stuff::getValue() const {auto self = const_cast<Stuff*>(this);  //  cast away const!if (!self->cacheValid) {self->cachedValue = LongComplicatedCalculation();self->cacheValid = true;}return self->cachedValue;
}

這是不推薦的做法!

為什么不能去掉 const

  • 違反接口契約getValue() 承諾不修改對象狀態,卻偷偷修改了。
  • 讓頭文件成為謊言:你聲稱不變,其實在改。
  • 代碼難以維護:別人調用你的 const 函數,會以為它是線程安全的、無副作用的,但其實不是。
  • 容易出 bug,尤其是涉及優化、多線程、拷貝等。

正確做法:使用 mutable

class Stuff {
private:int number1;double number2;int LongComplicatedCalculation() const;mutable int cachedValue;mutable bool cacheValid;
public:Stuff(int n1, double n2): number1(n1), number2(n2), cachedValue(0), cacheValid(false) {}bool Service1(int x);bool Service2(int y);int getValue() const;
};
int Stuff::getValue() const {if (!cacheValid) {cachedValue = LongComplicatedCalculation();cacheValid = true;}return cachedValue;
}

為什么 mutable 是好的解決方案?

優點說明
保持 const 函數語義只有緩存變量能被修改,接口保持誠實
可讀性好一眼能看出哪些成員可能在 const 函數中被改
編譯器優化友好保留 const 語義,有助于優化和靜態分析
更安全避免了錯誤地修改非緩存成員的風險

小結:

當你需要在 const 函數中修改內部緩存狀態時,請使用 mutable,而不是 const_cast。

永遠不要 cast away const 除非你非常清楚代價,并且這是最后手段。
mutable 是安全地修改緩存的標準做法。
如果你還想探討 mutable 的使用邊界或緩存設計模式,可以繼續問我。

你提到的是 C++ 核心準則中非常重要的一條資源管理原則:

I.11: Never transfer ownership by a raw pointer (T*)

永遠不要用裸指針(T*)傳遞資源所有權

違反規則的錯誤示例:

Policy* SetupAndPrice(args) {Policy* p = new Policy{...};  // 手動分配內存// ...return p;                     // 通過裸指針傳遞所有權
}
  • 🔺 誰來 delete? 不清楚。
  • 🔺 極易造成 內存泄漏
  • 🔺 調用方不知道是否需要釋放。
  • 🔺 所有權不明確,違反了現代 C++ 的資源管理理念。

更安全的替代方案:

1. 返回值傳遞(by value)

Policy SetupAndPrice(args);  // 編譯器可優化掉復制(RVO/NRVO)
  • 簡潔。
  • 現代編譯器通常會 自動省略拷貝
  • 如果不擔心復制代價,這是首選方式。

2. 使用非 const 引用傳入已有對象

void SetupAndPrice(Policy& policy);  // 調用方自己擁有 policy
  • 函數不會創建資源,只修改它。
  • 最適用于:調用前就已有對象。

3. 返回智能指針(推薦!)

std::unique_ptr<Policy> SetupAndPrice(args);
  • 明確表示“我擁有這個對象”。
  • 調用方拿到智能指針后,對象會自動銷毀。
  • 避免忘記 delete。

4. 使用 gsl::owner<T*>

gsl::owner<Policy*> SetupAndPrice(args);
  • 并不自動管理內存。
  • 作用是標記:“這個裸指針的所有權轉移了”
  • 更易被工具分析/被人理解。
template <class T, class = std::enable_if_t<std::is_pointer<T>::value>>
using owner = T;

小結:

做法安全性所有權是否清晰
裸指針返回 T*高風險不明確
返回值 T安全明確
智能指針 unique_ptr<T>安全明確
引用參數 T&安全明確
gsl::owner<T*>輔助作用明確但不自動

核心觀點:

內存管理太重要,不能只靠記憶。

不要手動管理內存,應該:

  • 用值語義(復制或移動)
  • 用智能指針管理所有權
  • 或至少用 owner<T*> 明確所有權

F.21: To return multiple “out” values, prefer returning a tuple or struct

返回多個“輸出”值時,優先返回 tuplestruct,不要用輸出參數(out-params)

傳統寫法:輸出參數

int foo(int inValue, int& outValue) {outValue = inValue * 2;return inValue * 3;
}
int main() {int number = 4;int answer = foo(5, number);return 0;
}

問題

  • number 是隱含的輸出值,看起來像輸入。
  • 函數返回值和“副作用輸出”分開,閱讀困難。
  • 不符合現代 C++ 倡導的值語義風格。

更好方式 1:自定義 struct

struct twoNumbers {int value1;int value2;
};
twoNumbers fooStruct(int inValue) {return twoNumbers{ inValue * 2, inValue * 3 };
}
int main() {twoNumbers result = fooStruct(6);int number = result.value1;int answer = result.value2;return 0;
}

優點

  • 清晰表達含義(用字段名說明含義)
  • 編譯器可優化拷貝(RVO)
  • 接口干凈,沒有輸出引用

更好方式 2:返回 std::tuple

std::tuple<int, int> fooTwo(int inValue) {return std::make_tuple(inValue * 2, inValue * 3);
}
使用 std::tie 拆解:
int number, answer;
std::tie(answer, number) = fooTwo(9);
使用結構化綁定(C++17 起):
auto [answer, number] = fooTwo(9);

優點

  • 表達力強,代碼簡潔
  • 結構化綁定讓讀取 tuple 更方便
    但 tuple 缺點是:字段無名稱,不夠語義化。如果語義重要,還是 struct 更好。

可選方式:std::optional<T>

如果你只是返回一個對象和一個“是否有效”的布爾值,可以用 std::optional<T>

std::optional<int> maybeDivide(int a, int b) {if (b == 0) return std::nullopt;return a / b;
}
int main() {auto result = maybeDivide(10, 0);if (result)std::cout << "Result: " << *result << '\n';elsestd::cout << "Division failed.\n";
}

為什么要避免輸出參數?

問題原因
不清晰輸出參數隱藏在函數簽名中
副作用函數修改了外部變量,閱讀成本高
可讀性差調用者必須準備變量來傳入修改
無法組合輸出參數難以用于鏈式表達式或惰性計算

總結:建議優先順序

目的推薦做法
返回多個有語義的值自定義 struct
返回多個簡單值std::tuple + 結構化綁定
返回可選單值std::optional<T>
不建議用引用參數 (int& out) 作為輸出

你提到的是現代 C++ 中推薦使用的 enum class(作用域枚舉),這是 C++11 引入的一項重要特性。下面逐條解釋你貼出的內容,并說明其意義。

使用 enum class 的好處

enum class Error { OK, FileNotFound, OutOfMemory };
enum class Ratings { Terrible, OK, Terrific };
enum oldStyle { OH, OK, OR };

傳統的 enum(如 oldStyle)的問題:

oldStyle Oklahoma = OK;
  • 你可以直接寫 OK,沒有作用域前綴。
  • 名字沖突:多個枚舉如果都有 OK,只能有一個能叫 OK。
  • 自動轉換為 int,可能造成隱式錯誤:
int x = OK;  // 自動轉 int,危險

enum class 的優勢

Error result = Error::OK;
Ratings stars = Ratings::OK;
int r = static_cast<int>(result);
  • 名字必須加作用域限定,例如 Error::OK,防止沖突。
  • 不會自動轉換為 int,必須顯式轉換:
int r = static_cast<int>(result);
  • 可以在不同枚舉里重復名字(每個都有自己的作用域)

更強類型、更安全

特性enumenum class
作用域限定
隱式轉為 int
可以重名(如都叫 OK)
類型安全(可當作獨立類型)
推薦舊風格強烈推薦

可指定底層類型(C++11 起)

enum class Error : uint8_t { OK, FileNotFound, OutOfMemory };
  • 默認底層類型是 int,但可以用更小(或大)的類型。
  • 適用于節省空間或做序列化通信協議。

實踐建議

  • 永遠使用 enum class,除非你明確需要與 C API 兼容。
  • 避免老式的 enum,尤其是放在頭文件里的(容易污染命名空間)。
  • 使用 static_cast<int>(e) 明確轉為整型。

示例總結:

enum class Error { OK, FileNotFound, OutOfMemory };
enum class Ratings { Terrible, OK, Terrific };
Error result = Error::OK;
Ratings stars = Ratings::OK;
// Cannot do this:
// int x = result;   錯誤
// Must be explicit:
int x = static_cast<int>(result);  // 

你提供的內容出自 C++ Core Guidelines(由 Kate Gregory 和 Bjarne Stroustrup 等人推動),主題是提高代碼的安全性、可讀性和意圖表達。我們逐條來解釋并 翻譯理解這些條目。

I.12: 使用 not_null 明確指針不能為空

Service s(1);
Service* ps = &s;
i = ps->DoSomething();
ps = nullptr;          //  潛在空指針異常
i = ps->DoSomething(); // 崩潰

使用 GSL(Guidelines Support Library)中的 not_null

#include <gsl/gsl>
gsl::not_null<Service*> ps = &s;
ps = nullptr; //  編譯失敗或運行時斷言

好處

  • 防止空指針解引用
  • 提升性能(不需要反復檢查指針是否為 nullptr
  • 表達意圖:這個指針不能為 null,不是“可能為 null”

避免不安全的類型轉換(ES.46)

C++ 中隱式轉換可能丟失信息,例如:

int x = 300;
char c = x; //  隱式縮窄,char 只有 8 位,丟失數據

使用 GSL 中的 narrownarrow_cast

#include <gsl/gsl>
int x = 300;
char c = gsl::narrow<char>(x);       //  拋異常(值改變了)
char c2 = gsl::narrow_cast<char>(x); //  允許丟失數據,但開發者明確知道這事

narrow vs narrow_cast 區別

功能narrow<T>(x)narrow_cast<T>(x)
類型轉換
運行時檢查拋出異常不檢查
有信息丟失時報錯安靜執行
使用目的安全性第一(調試優先)性能優先,但我知道后果

總結:為什么要用這些工具

工具目的幫助
gsl::not_null<T*>明確一個指針絕不能是 null編譯或運行時強制檢查
gsl::narrow<T>類型轉換必須安全運行時防止隱式精度丟失
gsl::narrow_cast<T>允許轉換但表達開發者意圖編譯時不報錯,清晰表達風險

最終目標

  • 編譯器和工具 幫你發現錯誤
  • 表達清晰的意圖,讓別人 看得懂你的代碼
  • 提前發現 bug,減少運行時崩潰

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

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

相關文章

Java并發編程實戰 Day 28:虛擬線程與Project Loom

【Java并發編程實戰 Day 28】虛擬線程與Project Loom 文章內容 在“Java并發編程實戰”系列的第28天&#xff0c;我們將聚焦于**虛擬線程&#xff08;Virtual Threads&#xff09;**和 Project Loom&#xff0c;這是 Java 在高并發場景下的一次重大革新。隨著現代應用對性能和…

Linux系統移植⑦:uboot啟動流程詳解-board_init_r執行過程

Linux系統移植⑦&#xff1a;uboot啟動流程詳解-board_init_r執行過程 在uboot中&#xff0c;board_init_r 是啟動流程中的一個關鍵函數&#xff0c;負責完成板級&#xff08;board-specific&#xff09;的后期初始化工作。以下是關于該函數的詳細說明&#xff1a; 1. 函數作…

OpenStack入門體驗

1.1云計算概述 相信大家都聽到很多的阿里云、騰訊云、百度云等等這些詞,那到底什么是云計算?云 計算又能做什么? 1.1.1什么是云計算 云計算(cloud computing)是一種基于網絡的超級計算模式,基于用戶的不同需求,提供所需的資源,包括計算資源、存儲資源、網絡資源等。云計算…

RK 安卓10/11平臺 HDMI-IN 調試

這篇文章我們介紹一下在安卓9、10、11的版本上&#xff0c;rk平臺的hdmi-in功能是如何實現的&#xff0c;下篇文章我們再介紹安卓12之后的版本有了什么變化。希望對在rk平臺調試hdmi-in功能的朋友有一些幫助。 目錄 &#xff08;1&#xff09;概述 &#xff08;2&#xff09;…

MongoDB學習記錄(快速入門)

MongoDB核心 基礎概念 數據庫 數據庫是按照數據結構來組織、存儲和管理數據的倉庫。在內存中運行的&#xff0c;一旦程序運行結束或者計算機斷電&#xff0c;程序運行中的數據都會丟失。我們需要將一些程序運行的數據持久化到硬盤之中&#xff0c;以確保數據的安全性。數據庫…

阿里一面:微服務拆分需要考慮什么因素?

要拆分微服務&#xff0c;首先我們要了解微服務拆了會有什么問題&#xff1f;怎么合理拆服務&#xff1f; 拆分服務會帶來什么問題&#xff1f; 舉個電商系統下單扣庫存的例子。 對于單體應用&#xff0c;通訊在進程內部進行&#xff0c;下單方法調用扣庫存方法&#xff0c;…

3D高斯潑濺和4D高斯

1.高斯函數 想象你往平靜的湖水里扔一塊石頭&#xff0c;水波會以石頭落點為中心向外擴散&#xff0c;形成一個逐漸衰減的圓形波紋。高斯函數的形狀就和這個波紋類似&#xff1a; 中心最高&#xff08;石頭落點&#xff0c;波峰最強&#xff09;。越往外&#xff0c;高度&…

comfyui插件和comfyui mac安裝

mac comfyui安裝包 ComfyUI.zip&#xff0c;官方最新0.3.40&#xff0c;如果后續官方有迭代&#xff0c;可以直接通過git更新源碼升級 comfyui插件下載&#xff0c;解壓放到custom_nodes目錄下&#xff0c;包含 comfyui-animatediff-evolved&#xff08;視頻插件&#xff09; 和…

面試題SpringCloud

SpringCloud有哪些特征&#xff1f; 分布式/版本化配置服務注冊與發現路由服務到服務的調用負載均衡斷路器領導選舉和集群狀態分布式消息傳遞 SpringCloud核心組件&#xff1f; Eureka 注冊中心Ribbon 客戶端負載均衡Hystrix&#xff1a; 服務容錯處理Feign:聲明式Rest客戶端Zu…

ASR-PRO語音識別可能出現的問題

ASR-PRO語音識別可能出現的問題 4月份有一天刷到牢大/愛麗絲語音自開關燈設備&#xff0c;心血來潮&#xff0c;博主也是淺嘗了一下&#xff0c;由此也總結一下&#xff0c;實現此項目會出現的問題。 在實現愛麗絲開關燈模塊時ASRPRO語音識別可能出現的問題如下&#xff1a; …

蒼穹外賣--緩存菜品Spring Cache

Spring Cache是一個框架&#xff0c;實現了基于注解的緩存功能&#xff0c;只需要簡單地加一個注解&#xff0c;就能實現緩存功能。 Spring Cache提供了一層抽象&#xff0c;底層可以切換不同的緩存實現&#xff0c;例如&#xff1a; ①EHCache ②Caffeine ③Redis 常用注解…

個人簡歷制作MarkDown模板

MarkDown制作個人簡歷的模板放在了github上&#xff0c;大家如有需求&#xff0c;請自取&#xff1a; https://github.com/QQQQQQBY/ResumeTemplate 介紹一下此模板的特點&#xff1a; &#x1f338;個人面試期間使用的、整理的簡歷格式&#xff0c;現在分享給大家。 ?簡歷采…

【MySQL數據庫 | 第五篇】DDL操作2

文章目錄 當前數據庫student的數據數據表操作 - 修改&刪除&#x1f4d6;修改操作增加字段&#x1f44f;案例&#xff1a;向數據表student中添加字段 id修改字段的數據類型【只能修改字段的屬性】&#x1f44f;案例&#xff1a;將student表中字段age的屬性由tinyint unsigne…

【瀏覽器插件】如何開發一個Chrome瀏覽器插件

這篇文章來介紹一下,如何開發一個自己的Chrome瀏覽器插件程序。 Chrome瀏覽器插件,其實是讓瀏覽器替我們執行我們自己寫的代碼,既然要讓瀏覽器執行代碼,那么首先,就需要定義一個規范,也就是說,需要讓Chrome瀏覽器知道,你寫的程序是一個插件。 這就需要介紹一下插件中…

詳細講解Redis為什么被設計成單線程

Redis 被設計成單線程的原因主要有以下幾點&#xff0c;這些原因涉及性能優化、復雜性控制、數據一致性以及適用場景等多個方面&#xff1a; 1. 簡化設計與實現 避免鎖競爭&#xff1a;多線程環境下&#xff0c;多個線程訪問共享資源時需要加鎖來保證數據一致性。鎖的使用會增…

Hive 邏輯優化器

Optimizer PointLookupOptimizer 作用&#xff1a;把符合條件的 OR 表達式轉為 IN。 參數hive.optimize.point.lookup 設置是否開啟 PointLookupOptimizer&#xff0c;默認為 true. 參數 hive.optimize.point.lookup.min 控制多少個 OR 表達式轉為 IN&#xff0c;默認 31。 例…

ZYNQ Petalinux實戰:PCIe直通NVMe固態硬盤,解鎖存儲性能新極限!

突破SD卡和SATA的速度枷鎖!本文將手把手教你如何在ZYNQ平臺上通過PCIe接口驅動NVMe固態硬盤。從硬件設計、Linux內核配置到創新性的DMA零拷貝優化,實現2000MB/s+ 的存儲性能飛躍,附完整代碼解析和性能實測對比。 一、為什么選擇PCIe NVMe?存儲性能革命 ZYNQ傳統存儲方案面…

05-mcp-server案例分享-用豆包大模型 1.6 手搓文生圖視頻 MCP-server發布到PyPI官網

1前言 上期給大家介紹過mcp-server案例分享-用豆包大模型 1.6 手搓文生圖視頻 MCP-server。當時部署的方式使用了一個私有云SSE的部署。當時缺少一個本地部署的方式&#xff0c;有的小伙伴給我留言能不能有一個本地話部署方式了。今天就給大家帶來一個本地化部署的方案。 話不…

MCP Parameters 增加描述

場景&#xff1a;本地MCP開發完后是否發現CLINE上顯示的Parameters 顯示No description 方法1 &#xff1a;使用參數元數據 (Annotated) 可以使用 Pydantic 的with 類提供有關參數的其他元數據Annotated。這種方法更受歡迎&#xff0c;因為它更現代&#xff0c;并且將類型提示…

STM32 GPIO 寄存器開發

&#x1f527; ?一、核心寄存器概覽? ?寄存器??功能??位寬??關鍵位域??GPIOx_CRL/CRH?配置引腳模式&#xff08;輸入/輸出/復用/模擬&#xff09;和輸出參數32位每4位控制1個引腳&#xff1a;CNF[1:0]&#xff08;模式&#xff09; MODE[1:0]&#xff08;速度&am…