C++11詳解(一) -- 列表初始化,右值引用和移動語義

文章目錄

  • 1.列表初始化
    • 1.1 C++98傳統的{}
    • 1.2 C++11中的{}
    • 1.3 C++11中的std::initializer_list
  • 2.右值引用和移動語義
    • 2.1左值和右值
    • 2.2左值引用和右值引用
    • 2.3 引用延長生命周期
    • 2.4左值和右值的參數匹配問題
    • 2.5右值引用和移動語義的使用場景
      • 2.5.1左值引用主要使用場景
      • 2.5.2移動構造和移動賦值
      • 2.5.3右值引用和移動語義解決傳值返回問題
        • 2.5.1右值對象構造,只有拷貝構造,沒有移動構造的場景->拷貝構造
        • 2.5.2右值對象構造,有拷貝構造,也有移動構造的場景->移動構造
        • 2.5.3右值對象賦值,只有拷貝構造和拷貝賦值,沒有移動構造和移動賦值的場景->拷貝構造和拷貝賦值
        • 2.5.4右值對象賦值,既有拷貝構造和拷貝賦值,也有移動構造和移動賦值的場景->移動構造和移動賦值
  • 3.面試經常問到的

1.列表初始化

1.1 C++98傳統的{}

C++98的{}主要支持數組結構體的初始化

struct Hello
{int _a;int _b;
};int main()
{int a[] = { 1,2,3,4,5 };int b[5] = { 0 };Hello c = { 1,2 };return 0;
}

1.2 C++11中的{}

  1. C++11規定了一切對象都可以用{}初始化,{}初始化也叫列表初始化
  2. 內置類型可以用{}初始化
  3. C++98支持單參數的類型轉換,也可以不用{}
Date d3 = { 2025 };// C++11
Date d4 = 2025;// C++98
string s = "11111";
// 單參數的支持隱式類型轉換
// 不支持,只有{}初始化才能省略=
// Date d7 2025;vector<Date> v;
v.push_back(d5);// 有名對象
v.push_back(Date( 2025,1,2 ));// 匿名對象
v.push_back({ 2025,1,1 });// {}map<string, string> dict; 
dict.insert({ "string","字符串" });
class Date
{
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}Date(const Date& d):_year(d._year), _month(d._month), _day(d._day){cout << "Date(const Date& d)" << endl;}
private:int _year;int _month;int _day;
};int main()
{// 1. 內置類型int x1 = { 2 };// 2.自定義類型,構造,隱式類型轉換,構造 + 拷貝構造// 優化為了直接構造Date d1 = { 2025,1,12 };// 直接調用構造Date d10(2025,1,1);// d2引用的是{2025,1,15}構造的臨時對象const Date& d2 = {2025,1,15};// 可以省略掉=Hello p{ 1,2 };int a{ 2 };Date d5{ 2025,1,1 };const Date& d6{ 2025,1,2 };return 0;
}

1.3 C++11中的std::initializer_list

  1. ?個vector對象,我想?N個值去構造初始化,那么我們得實現很多個構造函數才能?持,因為參數的個數不同
    vector v1 ={1,2,3};
    vector v2 = {1,2,3,4,5};
  2. C++11庫中提出了?個std::initializer_list的類底層是一個數組,將數據拷貝過來,std::initializer_list中有兩個指針,分別指向數組的開始和結束
  3. std::initializer_list支持迭代器遍歷
  4. 有了std::initializer_list就可以進行多個值的初始化,比如{x1,x2,x3…}
vector<int> v1 = {1,2,3,4};
vector<int> v2 = {10,20,30,1,2,3,4};
const vector<int>& v3 = {10,20,30,1,2,3,4};// {}初始化可以省略=
vector<int> v1{1,2,3,4};
vector<int> v2{10,20,30,1,2,3,4};
const vector<int>& v3{10,20,30,1,2,3,4};// initializer_list 構造
vector<int> v4({1,2,3,4,5,6});// a數組的指針和il1的兩個指針都在棧上,數組也在棧上
// a數組和這兩個指針的位置非常接近
initializer_list<int> il1 = {1,2,3};
int a[] = {1,2,3};
  1. map的initializer_list的初始化
    外層是initializer_list,內層是pair的鍵值對的初始化
// initializer_list + {}pair初始化的隱式類型轉換
map<string, string> dict = { {"sort","kai"},{"string","men"} };

2.右值引用和移動語義

1. C++98中的引用是左值引用,C++11中有了右值引用

type & x 左值引用
type && y 右值引用

2.1左值和右值

1.左值是一個表示數據的表達式(如變量名解引用的指針),一般是有持久狀態,存儲在內存中,我們可以獲取它的地址,左值可以出現賦值符號的左邊,也可以出現在賦值符號右邊。定義時const修飾符后的左值,不能給他賦值,但是可以取它的地址
2.右值也是?個表示數據的表達式,要么是字面值常量、要么是表達式求值過程中創建的臨時對象等,右值可以出現在賦值符號的右邊,但是不能出現出現在賦值符號的左邊,右值不能取地址
3.區分左值和右值的重要特點就是是否可以取地址

int main()
{// 1.左值 p,b,c,*p,s,s[0]// 變量int* p = new int(0);int b = 1;const int c = b;// 解引用*p = 10;// 有名對象string s("111111");// 函數的返回類型是引用s[0] = 'x';// 2.右值 10 x + y fmin(x,y) string("111")// 右值通常在寄存器中或者#define直接替換了// 所以不能夠直接取地址int x = 0, y = 0;// 字面量常量// 10// 表達式的返回值x + y;// 函數的返回值是存在寄存器中的或是臨時對象的拷貝fmin(x, y);// 匿名對象string("111");return 0;
}

2.2左值引用和右值引用

1. Type& r1 = x; Type&& rr1 = y;
第一個語句就是左值引用,左值引用就是給左值取別名;第二個就是右值引用,右值引用就是給右值取別名

左值引用取別名
int*& r1 = p;
int& r2 = b;
int& r6 = *p;
const int& r3 = c;
string& r4 = s;
char& r5 = s[0];右值引用取別名
int&& p1 = 10;
int&& p2 = x + y;
int&& p3 = fmin(x, y);
string&& p4 = string("111");

2. 左值引用不能直接引用右值,但是const左值引用可以引用右值,因為右值通常具有常性

對上面的解釋
1.右值到左值要權限放大(但是權限不能放大)
2.權限可以平移// 左值引?不能直接引?右值,但是const左值引?可以引?右值
const int& rx1 = 10;
const double& rx2 = x + y;
const double& rx3 = fmin(x, y);
const string& rx4 = string("11111");

3.右值引用不能直接引用左值,但是右值引用可以引用move(左值)

// 右值引?不能直接引?左值,但是右值引?可以引?move(左值)
int&& rrx1 = move(b);
int*&& rrx2 = move(p);
int&& rrx3 = move(*p);
string&& rrx4 = move(s);
// move的底層其實是強制類型轉換
// 把左值強轉為右值(s有名對象為左值)
string&& rrx5 = (string&&)s;

move實際是一個函數模版,其實也涉及到了引用折疊,后面會細講
在這里插入圖片描述

// (左值)強轉之后不會改變本身的屬性
// 強轉之后再使用左值,還是左值本身的屬性
// 用的只是臨時對象
// b、r1、rr1都是變量表達式,都是左值
cout << &b << endl;
cout << &r1 << endl;
cout << &rr1 << endl;int i = 1;
int* pi = (int*)i;
i還是int類型不會改變類型

4. 需要注意的是變量表達式都是左值屬性,也就意味著一個右值被右值引用綁定后,右值引用變量變量表達式的屬性是左值

左值引用的屬性是左值
右值引用的屬性也是左值
int&& rr1 = 10;
引用完rr1的屬性變為左值
rr1的屬性是左值,所以不能被右值引用綁定,除非move一下
int& rr6 = rr1;// 不報錯
int&& rrx6 = rr1;// 報錯
int&& rrx6 = move(rr1);

5. 在語法層面,左值引用和右值引用都是取別名,不開空間;在底層都是指針實現的

2.3 引用延長生命周期

1. 可以延長臨時對象和匿名對象的生命周期,臨時對象和匿名對象的生命周期只在當前的一行

std::string s1 = "Test";
const左值引用延長生命周期
const std::string& r1 = s1 + s1;
右值引用延長生命周期
std::string&& r2 = s1 + s1;
延長到r1和r2使用完

2.4左值和右值的參數匹配問題

1.C++98中,我們實現?個const左值引用作為參數的函數,那么實參傳遞左值和右值都可以匹配。

template<class T>
void func(const T& x)
{}
傳左值,權限縮小,左值傳左值
傳右值,權限平移,右值傳const左值

2. C++11以后,分別重載左值引用、const左值引用、右值引用作為形參的f函數,那么實參是左值會
匹配f(左值引用),實參是const左值會匹配f(const 左值引用),實參是右值會匹配f(右值引用),也就是編譯器會調用最匹配的類型,如果沒有右值引用,會調用const左值引用

void f(int& x)
{std::cout << "左值引用重載 f(" << x << ")\n";
}void f(const int& x)
{std::cout << "到 const 的左值引用重載 f(" << x << ")\n";
}void f(int&& x)
{std::cout << "右值引用重載 f(" << x << ")\n";
}int main()
{int i = 1;const int ci = 2;f(i); // 調用 f(int&)f(ci); // 調用 f(const int&)f(3); // 調用 f(int&&),如果沒有 f(int&&) 重載則會調用 f(const int&)f(std::move(i)); // 調用 f(int&&)return 0;
}

3. 右值引用變量在用于表達式時屬性是左值

    右值引用本身的屬性是左值int&& x = 1;f(x);調用f(int& x)f(std::move(x));調用f(int&& x)

2.5右值引用和移動語義的使用場景

2.5.1左值引用主要使用場景

1.左值引用的主要場景是在函數中,左值引用傳參左值引用傳返回值減少拷貝,同時左值引用傳參在函數中修改形參可以改變實參,傳引用返回可以修改返回對象
2.左值引用已經解決大多數場景的拷貝效率問題,但是有些場景不能使用傳左值引用返回,如addStrings和generate函數里面返回的是局部對象,C++98中的解決方案只能是被迫使用輸出型參數解決(傳值返回)。
3.那么C++11以后這里可以使用右值引用做返回值解決嗎?顯然是不可能的,因為這里的本質是返回對象是一個局部對象,函數結束這個對象就析構銷毀了,右值引用返回也無法概念對象已經析構銷毀的事實。

class Solution 
{
public:// 傳值返回需要拷?string addStrings(string num1, string num2) {string str;int end1 = num1.size() - 1, end2 = num2.size() - 1;// 進位int next = 0;while (end1 >= 0 || end2 >= 0){int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;int ret = val1 + val2 + next;next = ret / 10;ret = ret % 10;str += ('0' + ret);}if (next == 1)str += '1';reverse(str.begin(), str.end());return str;}
};class Solution 
{
public:
// 這?的傳值返回拷?代價就太?了
vector<vector<int>> generate(int numRows) 
{vector<vector<int>> vv(numRows);for(int i = 0; i < numRows; ++i){vv[i].resize(i+1, 1);}for(int i = 2; i < numRows; ++i){for(int j = 1; j < i; ++j){vv[i][j] = vv[i-1][j] + vv[i-1][j-1];}}return vv;
}
};

2.5.2移動構造和移動賦值

右值引用如何解決返回的對象是局部變量的問題?
1. 移動構造函數是一種構造函數,類似拷貝構造,要求第一個參數必須是類類型的引用,第一個參數必須是右值引用,拷貝構造是左值引用,如果有其他參數,必須有缺省值
2. 移動賦值是一個賦值運算符的重載,他跟拷貝賦值構成函數重載,類似拷貝賦值函數,移動賦值函數要求第一個參數是該類類型的引用,但是不同的是要求這個參數是右值引用
3. 對于像string/vector這樣的深拷貝的類或者包含深拷貝的成員變量的類,移動構造和移動賦值才有意義,因為移動構造和移動賦值的第一個參數都是右值引用的類型,它的本質是要“竊取”引用的右值對象的資源,而不是像拷貝構造和拷貝賦值那樣去拷貝資源,從提高效率

void swap(string& ss)
{::swap(_str, ss._str);::swap(_size, ss._size);::swap(_capacity, ss._capacity);
}// 移動構造
string(string&& s)
{// 右值引用本身具有左值的屬性// 因為要和this交換,左值可以修改值,右值不可以修改值cout << "string(string&& s) -> 移動構造" << endl;swap(s);// 交換需要的資源,轉移掠奪你的資源
}

在這里插入圖片描述

int main()
{string s1("111");string s2 = s1;string s3 = string("222");// s1本來的地址是xxxa510,現在s5的地址是a510// 說明移動構造掠奪了s1的資源給了s5string s5 = move(s1);return 0;
}

在這里插入圖片描述

2.5.3右值引用和移動語義解決傳值返回問題

2.5.1右值對象構造,只有拷貝構造,沒有移動構造的場景->拷貝構造

1. vs2019debug下,左邊為不優化的場景,傳值返回會發生拷貝構造,會產生臨時對象,臨時對象再拷貝構造ret,右邊的場景是直接優化為一次拷貝構造
2.vs2019release和vs2022下,會直接將str對象的構造,str拷貝構造臨時對象,臨時對象拷貝構造ret對象,合三為一,變為直接構造。本質就是str對象本質是ret對象的引用,底層是指針,str對象和ret對象的地址是一樣的,所以就沒有拷貝,沒有構造,只有引用了
3. Linux下也是和2022一樣的,編譯時用 g++ test.cpp -fno-elide-constructors 的方式關閉構造優化,就是兩次拷貝構造

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

2.5.2右值對象構造,有拷貝構造,也有移動構造的場景->移動構造

1. 傳值返回會被編譯器識別為右值,圖2展示了vs2019 debug環境下編譯器對拷貝的優化,左邊為不優化的情況下,兩次移動構造,右邊為編譯器優化的場景下連續步驟中的拷貝合二為一變為一次移動構造
2. 需要注意的是在vs2019的release和vs2022的debug和release,會直接將str對象的構造,str移動構造臨時對象,臨時對象移動構造ret對象,合三為一,變為直接構造。

在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述

2.5.3右值對象賦值,只有拷貝構造和拷貝賦值,沒有移動構造和移動賦值的場景->拷貝構造和拷貝賦值

1. 左圖不優化,一次拷貝構造,一次拷貝賦值,右圖優化為直接拷貝賦值,str是臨時對象的別名,直接用臨時對象拷貝賦值ret

在這里插入圖片描述
在這里插入圖片描述

2.5.4右值對象賦值,既有拷貝構造和拷貝賦值,也有移動構造和移動賦值的場景->移動構造和移動賦值

1. 需要注意的是在vs2019的release和vs2022的debug和release,下面代碼會進一步優化,直接構造要返回的臨時對象,str本質是臨時對象的引用,底層角度用指針實現。運行結果的角度,我們可以看到str的析構是在賦值以后,說明str就是臨時對象的別名。(臨時對象的生命周期只存在于當前行,賦值完之后就會銷毀)
2. 如果是傳值返回并且是右值對象,會移動你的資源,不用拷貝了

在這里插入圖片描述
在這里插入圖片描述

3.面試經常問到的

1. 左值引用和右值引用的最終目的是減少拷貝提高效率
2.左值引用還可以修改參數和返回值,比如輸出型參數(在函數體內修改參數可以影響實參)和operator

在這里插入圖片描述
3. 左值引用的不足:
部分函數返回場景,只能傳值返回,不能左值引用返回,比如當前函數的局部對象,出了當前函數的作用域,生命周期就到了,就銷毀了,不能左值引用返回,只能傳值返回
解決方案1,2,3:
1.不用返回值,用輸出型參數解決問題,不足:犧牲了可讀性
2.編譯器的優化
3.右值引用和移動語義

更早的編譯器只能使用這種輸出型參數,避免大量拷貝數據

class Solution 
{
public:void generate(int numRows, vector<vector<int>>& vv) {vector<vector<int>> vv(numRows);for (int i = 0; i < numRows; ++i){vv[i].resize(i + 1, 1);}for (int i = 2; i < numRows; ++i){for (int j = 1; j < i; ++j){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}
};int main()
{// vector<vector<int>> ret = Solution().generate(100);vector<vector<int>> ret;Solution().generate(100, ret);// 輸出型參數可以解決這個問題,傳引用過去,就不需要拷貝了return 0;
}

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

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

相關文章

在K8S中,pending狀態一般由什么原因導致的?

在Kubernetes中&#xff0c;資源或Pod處于Pending狀態可能有多種原因引起。以下是一些常見的原因和詳細解釋&#xff1a; 資源不足 概述&#xff1a;當集群中的資源不足以滿足Pod或服務的需求時&#xff0c;它們可能會被至于Pending狀態。這通常涉及到CPU、內存、存儲或其他資…

手寫MVVM框架-構建虛擬dom樹

MVVM的核心之一就是虛擬dom樹&#xff0c;我們這一章節就先構建一個虛擬dom樹 首先我們需要創建一個VNode的類 // 當前類的位置是src/vnode/index.js export default class VNode{constructor(tag, // 標簽名稱&#xff08;英文大寫&#xff09;ele, // 對應真實節點children,…

linux內核源代碼中__init的作用?

在 Linux 內核源代碼中&#xff0c;__init是一個特殊的宏&#xff0c;用于標記在內核初始化階段使用的變量或函數。這個宏的作用是告訴內核編譯器和鏈接器&#xff0c;被標記的變量或函數只在內核的初始化階段使用&#xff0c;在系統啟動完成后就不再需要了。因此&#xff0c;這…

【大數據技術】教程03:本機PyCharm遠程連接虛擬機Python

本機PyCharm遠程連接虛擬機Python 注意:本文需要使用PyCharm專業版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso寫在前面 本文主要介紹如何使用本地PyCharm遠程連接虛擬機,運行Python腳本,提高編程效率。 注意: …

pytorch實現門控循環單元 (GRU)

人工智能例子匯總&#xff1a;AI常見的算法和例子-CSDN博客 特性GRULSTM計算效率更快&#xff0c;參數更少相對較慢&#xff0c;參數更多結構復雜度只有兩個門&#xff08;更新門和重置門&#xff09;三個門&#xff08;輸入門、遺忘門、輸出門&#xff09;處理長時依賴一般適…

PAT甲級1032、sharing

題目 To store English words, one method is to use linked lists and store a word letter by letter. To save some space, we may let the words share the same sublist if they share the same suffix. For example, loading and being are stored as showed in Figure …

最小生成樹kruskal算法

文章目錄 kruskal算法的思想模板 kruskal算法的思想 模板 #include <bits/stdc.h> #define lowbit(x) ((x)&(-x)) #define int long long #define endl \n #define PII pair<int,int> #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); using na…

為何在Kubernetes容器中以root身份運行存在風險?

作者&#xff1a;馬辛瓦西奧內克&#xff08;Marcin Wasiucionek&#xff09; 引言 在Kubernetes安全領域&#xff0c;一個常見的建議是讓容器以非root用戶身份運行。但是&#xff0c;在容器中以root身份運行&#xff0c;實際會帶來哪些安全隱患呢&#xff1f;在Docker鏡像和…

js --- 獲取時間戳

介紹 使用js獲取當前時間戳 語法 Date.now()

ConcurrentHashMap線程安全:分段鎖 到 synchronized + CAS

專欄系列文章地址&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145290162 本文目標&#xff1a; 理解ConcurrentHashMap為什么線程安全&#xff1b;ConcurrentHashMap的具體細節還需要進一步研究 目錄 ConcurrentHashMap介紹JDK7的分段鎖實現JDK8的synchr…

Vue和Java使用AES加密傳輸

背景&#xff1a;Vue對參數進行加密&#xff0c;對響應進行解密。Java對參數進行解密&#xff0c;對響應進行解密。不攔截文件上傳類請求、GET請求。 【1】前端配置 安裝crypto npm install crypto-js編寫加解密工具類encrypt.js import CryptoJS from crypto-jsconst KEY …

開發板目錄 /usr/lib/fonts/ 中的字體文件 msyh.ttc 的介紹【微軟雅黑(Microsoft YaHei)】

本文是博文 https://blog.csdn.net/wenhao_ir/article/details/145433648 的延伸擴展。 本文是博文 https://blog.csdn.net/wenhao_ir/article/details/145433648 的延伸擴展。 問&#xff1a;運行 ls /usr/lib/fonts/ 發現有一個名叫 msyh.ttc 的字體文件&#xff0c;能介紹…

[ESP32:Vscode+PlatformIO]新建工程 常用配置與設置

2025-1-29 一、新建工程 選擇一個要創建工程文件夾的地方&#xff0c;在空白處鼠標右鍵選擇通過Code打開 打開Vscode&#xff0c;點擊platformIO圖標&#xff0c;選擇PIO Home下的open&#xff0c;最后點擊new project 按照下圖進行設置 第一個是工程文件夾的名稱 第二個是…

述評:如果抗拒特朗普的“普征關稅”

題 記 美國總統特朗普宣布對美國三大貿易夥伴——中國、墨西哥和加拿大&#xff0c;分別征收10%、25%的關稅。 他威脅說&#xff0c;如果這三個國家不解決他對非法移民和毒品走私的擔憂&#xff0c;他就要征收進口稅。 去年&#xff0c;中國、墨西哥和加拿大這三個國家&#…

九. Redis 持久化-AOF(詳細講解說明,一個配置一個說明分析,步步講解到位 2)

九. Redis 持久化-AOF(詳細講解說明&#xff0c;一個配置一個說明分析&#xff0c;步步講解到位 2) 文章目錄 九. Redis 持久化-AOF(詳細講解說明&#xff0c;一個配置一個說明分析&#xff0c;步步講解到位 2)1. Redis 持久化 AOF 概述2. AOF 持久化流程3. AOF 的配置4. AOF 啟…

C++11新特性之long long超長整形

1.介紹 long long 超長整形是C11標準新添加的&#xff0c;用于表示更大范圍整數的類型。 2.用法 占用空間&#xff1a;至少64位&#xff08;8個字節&#xff09;。 對于有符號long long 整形&#xff0c;后綴用“LL”或“II”標識。例如&#xff0c;“10LL”就表示有符號超長整…

瀏覽器查詢所有的存儲信息,以及清除的語法

要在瀏覽器的控制臺中查看所有的存儲&#xff08;例如 localStorage、sessionStorage 和 cookies&#xff09;&#xff0c;你可以使用瀏覽器開發者工具的 "Application" 標簽頁。以下是操作步驟&#xff1a; 1. 打開開發者工具 在 Chrome 或 Edge 瀏覽器中&#xf…

基于Springboot框架的學術期刊遴選服務-項目演示

項目介紹 本課程演示的是一款 基于Javaweb的水果超市管理系統&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 2.帶你從零開始部署運行本套系統 3.該項目附…

新版231普通阿里滑塊 自動化和逆向實現 分析

聲明: 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向過程 補環境逆向 部分補環境 …

java-(Oracle)-Oracle,plsqldev,Sql語法,Oracle函數

卸載好注冊表,然后安裝11g 每次在執行orderby的時候相當于是做了全排序,思考全排序的效率 會比較耗費系統的資源,因此選擇在業務不太繁忙的時候進行 --給表添加注釋 comment on table emp is 雇員表 --給列添加注釋; comment on column emp.empno is 雇員工號;select empno,en…