偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

別再用 vector<bool> 了!Google 高級(jí)工程師:這可能是 STL 最大的設(shè)計(jì)失誤

開(kāi)發(fā)
今天我們來(lái)聊一個(gè)藏在C++標(biāo)準(zhǔn)庫(kù)中的"定時(shí)炸彈",它看起來(lái)人畜無(wú)害,但卻坑了無(wú)數(shù)C++程序員。

嘿,各位碼農(nóng)兄弟姐妹們!今天咱們來(lái)聊一個(gè)你可能每天都在用,但是卻從來(lái)沒(méi)注意過(guò)的C++小怪獸:vector<bool>。

前幾天,我在幫同事調(diào)一個(gè)莫名奇妙的bug,看到他代碼里用了一堆vector<bool>來(lái)存儲(chǔ)狀態(tài)標(biāo)志。我隨口問(wèn)了一句:"你知道這玩意兒不是真正的 vector 嗎?"

他一臉懵逼:"啥?不可能吧?名字明明白白寫(xiě)著 vector ?。?

就是這樣,在C++的世界里,vector<bool>其實(shí)是個(gè)披著vector外衣的奇葩東西!據(jù)說(shuō)在Google內(nèi)部的一次技術(shù)分享中,一位高級(jí)工程師直言不諱地稱(chēng)它為"STL中最大的設(shè)計(jì)失誤之一"。這不是我瞎編的,在C++標(biāo)準(zhǔn)委員會(huì)的多份提案文件中,也多次討論過(guò)這個(gè)問(wèn)題,甚至想在新標(biāo)準(zhǔn)中"修正"它,但又擔(dān)心破壞向后兼容性。

今天我就來(lái)給大家扒一扒這個(gè)C++界的"貓頭鷹"(白天是鳥(niǎo),晚上是貓...不,是看起來(lái)像vector,實(shí)際不是vector)到底坑在哪里。保證講得通俗易懂,小白也能看明白,包你看完直呼"漲姿勢(shì)了"!

一、vector是個(gè)什么妖怪?

1. 正常的vector是啥樣?

在深入了解vector<bool>之前,我們得先搞清楚一個(gè)普通的 vector 該是啥樣的。

想象一下,vector就像是一排連續(xù)的小格子,每個(gè)格子里放一個(gè)元素。當(dāng)你用vector<int>時(shí),每個(gè)格子大小固定為4字節(jié)(在大多數(shù)平臺(tái)上),整齊劃一地排列著:

vector<int> normal_vec = {1, 2, 3};
int& first = normal_vec[0];  // 拿到第一個(gè)元素的引用
first = 100;  // 修改這個(gè)引用
cout << normal_vec[0];  // 輸出100,沒(méi)問(wèn)題!

一切正常,對(duì)吧?你可以獲取 vector 中元素的引用,然后通過(guò)引用修改元素值。這就是 C++ 引用的基本用法,相當(dāng)于給同一塊內(nèi)存起了個(gè)別名,通過(guò)別名修改內(nèi)存就是修改原始數(shù)據(jù)。

2. 再看vector<bool>

現(xiàn)在我們來(lái)試試 bool 版本的:

vector<bool> weird_vec = {true, false, true};
bool& first = weird_vec[0];  // 嗯?這行編譯不過(guò)!

等一下!上面這行代碼竟然編譯不過(guò)!為啥?因?yàn)関ector<bool>[0]返回的根本不是bool&!

怎么回事?打開(kāi)STL源碼看看(為了便于理解,我簡(jiǎn)化了一下):

template <typename T>
class vector {
public:
    T& operator[](size_t n) { return _data[n]; }
    // ...其他成員...
};

// 但是對(duì)于bool有特殊版本!
template <>
class vector<bool> {
public:
    // 注意返回類(lèi)型不是bool&
    reference operator[](size_t n) { /* 特殊實(shí)現(xiàn) */ }
    // ...其他成員...
};

看到?jīng)]?普通的 vector 返回的是T&,但vector<bool>返回的是一個(gè)叫reference的東西,它不是真正的bool&,而是一個(gè)代理類(lèi)(proxy class)!

實(shí)際上,vector<bool>為了節(jié)省空間,內(nèi)部做了特殊處理:它不是存儲(chǔ)bool值,而是把8個(gè)bool打包成一個(gè)字節(jié)來(lái)存!讓我用一個(gè)簡(jiǎn)單的圖來(lái)說(shuō)明:

vector<bool> v_bool = { true, false, true };

內(nèi)存布局:
+------------------------+
| 10100000 | .... | .... |
+------------------------+
   ↑↑↑        
   |||
   ||+--- 第3個(gè)元素 (true = 1)
   |+---- 第2個(gè)元素 (false = 0)
   +----- 第1個(gè)元素 (true = 1)


# 對(duì)于普通的vector<int>或其他類(lèi)型,每個(gè)元素會(huì)占用完整的內(nèi)存單元
vector<int> v_int = { 1, 0, 1 };

內(nèi)存布局:
+--------+--------+--------+
|   1    |   0    |   1    |
+--------+--------+--------+
 4字節(jié)    4字節(jié)     4字節(jié)

與普通 vector 不同,vector<bool>在內(nèi)部使用了位壓縮存儲(chǔ)。一個(gè)字節(jié)(8位)可以存儲(chǔ)8個(gè)bool值,這就是它能節(jié)省空間的原因。

但這種存儲(chǔ)方式帶來(lái)了一個(gè)問(wèn)題:C++中的引用必須指向一個(gè)完整的對(duì)象,不能指向?qū)ο蟮囊徊糠治挥?。所以vector<bool>不能像其他 vector 一樣返回元素的引用,而是返回一個(gè)特殊的代理對(duì)象,這個(gè)對(duì)象會(huì)記住元素的位置信息,并在需要時(shí)執(zhí)行必要的位運(yùn)算來(lái)讀取或修改那一位。

這聽(tīng)起來(lái)是不是很像那些"掛羊頭賣(mài)狗肉"的餐館?你以為點(diǎn)的是"醬爆羊肉",結(jié)果端上來(lái)的是"醬爆雞肉假扮的羊肉"...

二、vector<bool>有什么坑?

坑1:引用返回不了,許多常見(jiàn)操作失效

我們來(lái)看一個(gè)更具體的例子:

// 普通vector
vector<int> v_int(10, 0);
int* ptr = &v_int[0];  // 正常
int& ref = v_int[0];   // 正常

// 但對(duì)于vector<bool>
vector<bool> v_bool(10, false);
bool* ptr = &v_bool[0];  // 編譯錯(cuò)誤!
bool& ref = v_bool[0];   // 編譯錯(cuò)誤!

為啥會(huì)出錯(cuò)?因?yàn)関_bool[0]返回的是一個(gè)臨時(shí)對(duì)象,不是真正的bool,你不能對(duì)臨時(shí)對(duì)象取地址或綁定非常量引用。

這導(dǎo)致的一個(gè)嚴(yán)重后果是,很多依賴于引用語(yǔ)義的算法或操作在vector<bool>上會(huì)失效。

坑2:迭代器行為異常

迭代器在STL中扮演著至關(guān)重要的角色,但vector<bool>的迭代器行為與普通vector完全不同:

vector<int> v_int = {1, 2, 3};
auto it = v_int.begin();
*it = 10;  // 沒(méi)問(wèn)題,修改了第一個(gè)元素

vector<bool> v_bool = {true, false, true};
auto it2 = v_bool.begin();
bool val = *it2;  // 獲取值沒(méi)問(wèn)題
*it2 = false;     // 看起來(lái)也沒(méi)問(wèn)題

bool& ref = *it2;  // 編譯錯(cuò)誤!

最后那行代碼會(huì)報(bào)錯(cuò),因?yàn)?it2返回的是一個(gè)臨時(shí)對(duì)象,不是真正的bool引用。

這個(gè)例子完美展示了vector<bool>的特殊性:對(duì)于普通vector,你可以獲取元素的引用;但對(duì)于vector<bool>,你只能獲取一個(gè)臨時(shí)代理對(duì)象。這個(gè)代理對(duì)象可以轉(zhuǎn)換為 bool 值,也可以接受賦值,但它不是引用。

這種差異在使用標(biāo)準(zhǔn)算法時(shí)尤其成問(wèn)題:

// 對(duì)普通vector能正常工作
vector<int> nums = {1, 2, 3};
transform(nums.begin(), nums.end(), nums.begin(), 
          [](int& x) { return x * 2; });  // 正常

// 但對(duì)vector<bool>會(huì)失敗
vector<bool> flags = {true, false, true};
transform(flags.begin(), flags.end(), flags.begin(),
          [](bool& x) { return !x; });  // 編譯錯(cuò)誤!

當(dāng)編寫(xiě)泛型代碼時(shí),這種不一致性可能導(dǎo)致難以調(diào)試的問(wèn)題。

坑3:作為模板參數(shù)時(shí)與其他類(lèi)型不一致

當(dāng)你寫(xiě)一個(gè)通用模板函數(shù),本來(lái)期望它能處理各種vector類(lèi)型,結(jié)果vector<bool>卻讓你失望了:

template <typename T>
void process_vector(vector<T>& vec) {
    T& first = vec[0];  // 當(dāng)T是bool時(shí),這行爆炸!
    // ...處理邏輯...
}

vector<int> vi = {1, 2, 3};
process_vector(vi);  // 沒(méi)問(wèn)題

vector<bool> vb = {true, false, true};
process_vector(vb);  // 轟!編譯錯(cuò)誤!

這導(dǎo)致你要么放棄使用vector<bool>,要么為它寫(xiě)特殊處理代碼,破壞了泛型編程的一致性。

坑4:與C API交互困難

假設(shè)你需要調(diào)用一個(gè)C API,它接受bool數(shù)組指針:

// C API
extern"C"void process_flags(bool* flags, size_t count);

// 如果用普通數(shù)組
bool arr[100] = {false};
process_flags(arr, 100);  // 正常工作

// 如果用vector<int>
vector<int> vi(100, 0);
process_flags(reinterpret_cast<bool*>(vi.data()), vi.size());  // 勉強(qiáng)可以

// 如果用vector<bool>
vector<bool> vb(100, false);
process_flags(vb.data(), vb.size());  // 編譯錯(cuò)誤!vector<bool>沒(méi)有data()方法!

vector<bool>由于內(nèi)部實(shí)現(xiàn)特殊,沒(méi)有提供直接訪問(wèn)底層內(nèi)存的方法,這使得它與C API交互變得異常困難。

坑5:并發(fā)編程中的噩夢(mèng)

在多線程環(huán)境下,vector<bool>可能導(dǎo)致更嚴(yán)重的問(wèn)題:

vector<bool> flags(100, false);

// 線程1
flags[10] = true;

// 線程2(同時(shí))
flags[11] = true;

因?yàn)関ector<bool>內(nèi)部可能8個(gè)bool值壓縮在一個(gè)字節(jié)里,當(dāng)兩個(gè)線程同時(shí)修改相鄰的位,它們實(shí)際上可能在修改同一個(gè)字節(jié)的不同位!這會(huì)導(dǎo)致數(shù)據(jù)競(jìng)爭(zhēng),即使從邏輯上看它們修改的是不同的元素。

這種問(wèn)題在普通vector中是不會(huì)發(fā)生的,因?yàn)槊總€(gè)元素都是獨(dú)立的內(nèi)存區(qū)域。

坑6:常見(jiàn)的性能陷阱

雖然vector<bool>的設(shè)計(jì)初衷是為了節(jié)省空間,但在某些情況下,它實(shí)際上可能導(dǎo)致性能下降:

// 設(shè)置一百萬(wàn)個(gè)標(biāo)志
vector<bool> flags(1000000);
for (int i = 0; i < 1000000; i++) {
    flags[i] = (i % 2 == 0);  // 每次賦值都涉及位操作
}

// 相比之下,普通數(shù)組可能更快
bool* arr = new bool[1000000];
for (int i = 0; i < 1000000; i++) {
    arr[i] = (i % 2 == 0);  // 簡(jiǎn)單的內(nèi)存寫(xiě)入
}

由于vector<bool>每次賦值都需要計(jì)算位置并進(jìn)行位操作,它的寫(xiě)入性能可能比直接使用bool數(shù)組要差。當(dāng)然,這取決于具體的使用場(chǎng)景和編譯器優(yōu)化。

三、怎么避坑?

既然知道了vector<bool>是個(gè)大坑,那我們?cè)趺幢荛_(kāi)它呢?根據(jù)不同的使用場(chǎng)景,有多種替代方案:

方案1:用vector<char>或vector<uint8_t>

最簡(jiǎn)單的替代方案是用vector<char>或vector<uint8_t>,這樣每個(gè)bool值仍然占用一個(gè)字節(jié),但行為與其他vector一致:

vector<char> better_bools(100, 0);  // 0表示false
better_bools[50] = 1;  // 1表示true

char& ref = better_bools[50];  // 可以獲取引用,沒(méi)問(wèn)題!

這種方案的優(yōu)點(diǎn)是簡(jiǎn)單直觀,符合 vector 的一般行為,缺點(diǎn)是不如vector<bool>節(jié)省空間。

方案2:用deque<bool>或list<bool>

另一個(gè)選擇是使用其他容器,如deque<bool>或list<bool>:

deque<bool> deque_bools = {true, false, true};
bool& first = deque_bools[0];  // 這行沒(méi)問(wèn)題!

這些容器沒(méi)有為bool類(lèi)型做特殊優(yōu)化,所以它們的行為與其他類(lèi)型一致。不過(guò),它們的內(nèi)存布局和性能特性與vector不同,使用前需要考慮你的具體需求。

方案3:如果真要省空間,用std::bitset或動(dòng)態(tài)位集

如果空間效率確實(shí)很重要,可以考慮使用std::bitset或第三方的動(dòng)態(tài)位集庫(kù):

// 固定大小的位集
bitset<100> bits;
bits[0] = true;
bits[1] = false;

// 如果需要?jiǎng)討B(tài)大小,可以考慮boost::dynamic_bitset
#include <boost/dynamic_bitset.hpp>
boost::dynamic_bitset<> dyn_bits(100);
dyn_bits[0] = true;

bitset和dynamic_bitset明確告訴你它們是按位存儲(chǔ)的,API設(shè)計(jì)也是針對(duì)位操作的,不會(huì)讓你產(chǎn)生"這是普通容器"的誤解。

方案4:用現(xiàn)代C++的std::span

在C++20中,引入了std::span,它可以提供對(duì)連續(xù)序列的視圖:

#include <span>    // 用于std::span
  
// C++20
vector<char> storage(100, 0);  // 底層存儲(chǔ)
span<bool> bool_view(reinterpret_cast<bool*>(storage.data()), storage.size());

// 現(xiàn)在可以當(dāng)作bool數(shù)組使用
bool_view[10] = true;

span本身不擁有存儲(chǔ)空間,只是提供一個(gè)視圖,所以它的行為更加可預(yù)測(cè)。不過(guò),這需要C++20支持,而且你仍然需要自己管理底層存儲(chǔ)。

方案5:自定義BoolVector類(lèi)(完整實(shí)戰(zhàn)例子)

如果你需要一個(gè)完全符合vector語(yǔ)義的bool容器,可以自己實(shí)現(xiàn)一個(gè):

#include <vector>
#include <iostream>
usingnamespacestd;

// 自定義一個(gè)與vector接口一致的bool容器
class BoolVector {
private:
    vector<char> data;  // 用char存bool,確保每個(gè)元素獨(dú)立

public:
    // 構(gòu)造函數(shù)
    BoolVector() = default;
    BoolVector(size_t size, bool value = false) : data(size, value) {}
    
    // 從初始化列表構(gòu)造
    BoolVector(initializer_list<bool> il) {
    data.reserve(il.size());  // 預(yù)分配空間以提高效率
    for (bool value : il) {
        data.push_back(value);  // 將bool值轉(zhuǎn)換為char存儲(chǔ)
    }
}
    
    // 添加元素
    void push_back(bool value) {
        data.push_back(value);
    }
    
    // 訪問(wèn)元素(返回引用?。?    bool& operator[](size_t pos) {
        returnreinterpret_cast<bool&>(data[pos]);
    }
    
    // 常量版本
    constbool& operator[](size_t pos) const {
        returnreinterpret_cast<constbool&>(data[pos]);
    }
    
    // 獲取大小
    size_t size() const {
        return data.size();
    }
    
    // 判斷是否為空
    bool empty() const {
        return data.empty();
    }
    
    // 調(diào)整大小
    void resize(size_t new_size, bool value = false) {
        data.resize(new_size, value);
    }
    
    // 預(yù)留空間
    void reserve(size_t new_capacity) {
        data.reserve(new_capacity);
    }
    
    // 清空
    void clear() {
        data.clear();
    }
    
    // 支持迭代器
    typedefchar* iterator;
    typedefconstchar* const_iterator;
    
    iterator begin() { return &data[0]; }
    iterator end() { return &data[0] + data.size(); }
    
    const_iterator begin() const { return &data[0]; }
    const_iterator end() const { return &data[0] + data.size(); }
};

// 使用示例
int main() {
    BoolVector my_bools(3, false);
    my_bools[0] = true;
    
    bool& first = my_bools[0];  // 可以獲取引用!
    first = false;
    
    cout << "第一個(gè)元素: " << (my_bools[0] ? "true" : "false") << endl;
    
    // 支持迭代
    for (auto& b : my_bools) {
        cout << (b ? "true" : "false") << " ";
    }
    cout << endl;
    
    // 支持push_back
    my_bools.push_back(true);
    cout << "大小: " << my_bools.size() << endl;
    
    return0;
}

這個(gè)自定義的BoolVector類(lèi)雖然占用空間比vector<bool>大,但行為與其他vector一致,不會(huì)給你帶來(lái)意外驚喜。當(dāng)然,這只是一個(gè)簡(jiǎn)化版本,完整實(shí)現(xiàn)還需要添加更多方法和優(yōu)化。

四、為什么會(huì)有這種設(shè)計(jì)?

說(shuō)實(shí)話,vector<bool>的設(shè)計(jì)初衷是好的——節(jié)省內(nèi)存空間。畢竟 bool 值只需要1個(gè)位就能表示,但C++中 bool 類(lèi)型卻占了1個(gè)字節(jié)(8位)。在內(nèi)存非常寶貴的年代,這種優(yōu)化是有意義的。

實(shí)際上,vector<bool>的特化是在C++98標(biāo)準(zhǔn)中引入的,那時(shí)候:

  • C++標(biāo)準(zhǔn)庫(kù)剛剛形成,很多設(shè)計(jì)理念還不成熟
  • 內(nèi)存資源相對(duì)珍貴,節(jié)省空間被認(rèn)為比API一致性更重要
  • 泛型編程和模板元編程的技術(shù)還沒(méi)有充分發(fā)展
  • 人們對(duì)"概念(Concept)"和"類(lèi)型特征(Type Traits)"的理解還不夠深入

在當(dāng)時(shí)看來(lái),vector<bool>的空間優(yōu)化似乎是一個(gè)不錯(cuò)的主意。但隨著時(shí)間推移,人們逐漸認(rèn)識(shí)到這種設(shè)計(jì)破壞了容器的抽象性和一致性,帶來(lái)的麻煩遠(yuǎn)大于好處。

這就像是開(kāi)發(fā)團(tuán)隊(duì)想給你省錢(qián),結(jié)果卻不小心把你的錢(qián)包丟了...

現(xiàn)在C++標(biāo)準(zhǔn)委員會(huì)已經(jīng)認(rèn)識(shí)到了這個(gè)問(wèn)題,但由于向后兼容性的考慮,不能直接改變vector<bool>的行為。在C++17和C++20標(biāo)準(zhǔn)中,已經(jīng)引入了更好的位集合處理方案,但vector<bool>這個(gè)"歷史遺留問(wèn)題"仍然存在。

五、現(xiàn)代C++中的最佳實(shí)踐

隨著C++的發(fā)展,處理bool集合的最佳實(shí)踐也在不斷演進(jìn)。在現(xiàn)代C++項(xiàng)目中,我推薦以下做法:

1. 明確你的需求

首先要思考你真正需要的是什么:

  • 需要高效的隨機(jī)訪問(wèn)和修改?考慮vector<char>
  • 需要節(jié)省空間?考慮bitset或dynamic_bitset
  • 需要頻繁插入刪除?考慮deque<bool>或list<bool>
  • 需要與C API交互?使用原生bool數(shù)組

2. 用適當(dāng)?shù)姆庋b隱藏實(shí)現(xiàn)細(xì)節(jié)

封裝實(shí)現(xiàn)細(xì)節(jié)通常是個(gè)好主意,但不是絕對(duì)必要的。具體選擇應(yīng)該取決于實(shí)際需求:

class FlagManager {
private:
    vector<char> flags_;  // 內(nèi)部實(shí)現(xiàn)

public:
    // 提供bool語(yǔ)義的接口
    bool get(size_t index) const {
        return flags_[index] != 0;
    }
    
    void set(size_t index, bool value) {
        flags_[index] = value;
    }
    
    // ...其他方法...
};

這樣,即使將來(lái)實(shí)現(xiàn)變了,用戶代碼也不需要改變。

封裝的好處是隔離實(shí)現(xiàn)細(xì)節(jié),但并非所有場(chǎng)景都需要這種抽象層級(jí)。對(duì)于簡(jiǎn)單引用,直接使用替代容器可能更清晰;而對(duì)于大型項(xiàng)目,適當(dāng)封裝則能夠提供更好的維護(hù)性。

3. 考慮使用std::span(C++20)

如前所述,C++20的std::span提供了一個(gè)靈活的非擁有視圖,可以用來(lái)處理bool序列:

void process_flags(span<bool> flags) {
    for (bool& flag : flags) {
        // 處理每個(gè)標(biāo)志
    }
}

// 調(diào)用
vector<char> storage(100);
process_flags({reinterpret_cast<bool*>(storage.data()), storage.size()});

4. 使用強(qiáng)類(lèi)型枚舉代替單個(gè)bool

當(dāng)你需要表示多個(gè)相關(guān)的狀態(tài)時(shí),考慮使用強(qiáng)類(lèi)型枚舉而不是多個(gè)bool:

// 不好:多個(gè)分散的bool
bool is_active;
bool is_visible;
bool is_enabled;

// 更好:使用枚舉
enumclass ItemState {
    Inactive = 0,
    Active = 1,
    Visible = 2,
    Enabled = 4
};

// 使用位操作
ItemState state = ItemState::Active | ItemState::Visible;

這樣不僅代碼更清晰,而且避免了處理多個(gè)bool的麻煩。

六、總結(jié):避開(kāi)這個(gè)STL的"設(shè)計(jì)失誤"

總結(jié)一下:

  • vector<bool>不是真正的vector,而是對(duì)bool做了特殊優(yōu)化的容器適配器
  • 它的行為與其他vector不一致,在引用、迭代器和并發(fā)等方面可能導(dǎo)致意想不到的錯(cuò)誤
  • 替代方案包括vector<char>、deque<bool>、bitset和自定義容器,根據(jù)具體需求選擇合適的方案
  • 現(xiàn)代C++提供了更多工具來(lái)解決這個(gè)問(wèn)題,如std::span和強(qiáng)類(lèi)型枚舉

最后,我想說(shuō)的是,C++的設(shè)計(jì)哲學(xué)一向是"你不用的,你不付費(fèi)"。但vector<bool>違背了這一哲學(xué),它是少數(shù)幾個(gè)會(huì)讓你"被迫付費(fèi)"的特性之一——即使你不需要空間優(yōu)化,也不得不面對(duì)它與眾不同的行為。

所以,下次當(dāng)你想要一個(gè)bool的vector時(shí),三思而后行,問(wèn)問(wèn)自己:我真的需要vector<bool>嗎?還是其他替代方案更適合我的需求?

PS: 你知道嗎?vector<bool>的這個(gè)"特例化"還有一個(gè)專(zhuān)業(yè)術(shù)語(yǔ)叫做"概念破壞者(concept breaker)",因?yàn)樗茐牧?容器"這個(gè)概念應(yīng)有的一致性。這也是為什么在C++20的概念(Concepts)機(jī)制中,它不滿足某些對(duì)常規(guī)容器的約束。有趣的是,C++標(biāo)準(zhǔn)委員會(huì)曾經(jīng)考慮過(guò)引入一個(gè)真正的位向量類(lèi)型來(lái)替代vector<bool>,但由于向后兼容性的考慮,最終沒(méi)有這樣做。相反,他們選擇在標(biāo)準(zhǔn)中明確指出vector<bool>的特殊行為,并建議開(kāi)發(fā)者在需要位集合時(shí)使用其他替代方案。

責(zé)任編輯:趙寧寧 來(lái)源: 跟著小康學(xué)編程
相關(guān)推薦

2022-08-23 08:00:00

高級(jí)工程師軟件工程師代碼庫(kù)

2021-11-03 16:10:16

RedisJava內(nèi)存

2020-12-18 11:55:27

編程面試

2023-01-11 08:24:32

2010-12-24 10:47:48

網(wǎng)絡(luò)規(guī)劃設(shè)計(jì)師

2023-05-29 16:09:22

JavaScript技能瀏覽器

2017-05-15 12:58:00

編程javaapl

2010-12-24 10:50:43

系統(tǒng)架構(gòu)設(shè)計(jì)師

2015-05-11 09:38:42

.NET高級(jí)工程師面試題

2023-08-11 13:25:00

JavaScript

2021-08-27 10:14:22

機(jī)器學(xué)習(xí)工具手冊(cè)人工智能

2018-09-20 10:55:38

數(shù)據(jù)庫(kù)順豐高級(jí)工程師

2024-08-28 11:56:33

2018-10-25 09:37:02

Docker入門(mén)容器

2023-02-26 00:00:01

Spring數(shù)據(jù)庫(kù)組件

2023-02-26 10:14:51

Spring第三方庫(kù)

2021-09-30 07:25:32

數(shù)據(jù)分析數(shù)據(jù)分析師工具

2020-03-05 15:12:51

數(shù)據(jù)分析人工智能運(yùn)營(yíng)

2015-05-11 15:06:00

軟件工程師寫(xiě)代碼

2018-11-05 08:10:30

Netty架構(gòu)模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)