當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]讓我們從std::make_unique和std::make_shared之間的比較開始講起吧。std::make_shared是C++11的一部分,可惜的是,std::make_unique不是,它

讓我們從std::make_unique和std::make_shared之間的比較開始講起吧。std::make_shared是C++11的一部分,可惜的是,std::make_unique不是,它在C++14才納入標(biāo)準(zhǔn)庫(kù)。如果你使用的是C++11,不用憂傷,因?yàn)閟td::make_unique的簡(jiǎn)單版本很容易寫出來(lái),不信你看:


templatestd::unique_ptrmake_unique(Ts&&...?params)
{
????return?std::unique_ptr(new?T(std::forward(params)...));
}

就像你看到的那樣,make_unique只是把參數(shù)完美轉(zhuǎn)發(fā)給要?jiǎng)?chuàng)建對(duì)象的構(gòu)造函數(shù),再?gòu)膎ew出來(lái)的原生指針構(gòu)造std::unique_ptr,最后返回創(chuàng)建的std::unique_ptr。這種形式的函數(shù)不支持?jǐn)?shù)組和自定義刪除器,但它說(shuō)明了只要一點(diǎn)點(diǎn)工作,你就可以創(chuàng)造你需要的make_unique了。你要記住不要把你自己的版本放入命名空間std,因?yàn)楫?dāng)你提升到C++14標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)的時(shí)候,你不會(huì)想要它和標(biāo)準(zhǔn)庫(kù)的版本沖突。

std::make_unique和std::make_shared是三個(gè)make函數(shù)中的其中兩個(gè),而make函數(shù)是:把任意集合的參數(shù)完美轉(zhuǎn)發(fā)給動(dòng)態(tài)分配對(duì)象的構(gòu)造函數(shù),然后返回一個(gè)指向那對(duì)象的智能指針。第三個(gè)make函數(shù)是std::allocate_shared,它的行為與std::make_shared類似,除了它第一個(gè)參數(shù)是個(gè)分配器,指定動(dòng)態(tài)分配對(duì)象的方式。

通過(guò)瑣碎比較使用make函數(shù)和不使用make函數(shù)創(chuàng)建智能指針,揭露了使用make函數(shù)更可取的第一個(gè)原因??紤]以下:


auto?upw1(std::make_unique());?????//?使用make函數(shù)
std::unique_ptrupw2(new?Widget);??//?不使用make函數(shù)
auto?spw1(std::make_shared());?????//?使用make函數(shù)
std::shared_ptrspw2(new?Widget);??//?不使用make函數(shù)

它們本質(zhì)上的不同是:使用new的版本重復(fù)著需要?jiǎng)?chuàng)建的類型(即出現(xiàn)了兩次Widget),而使用make函數(shù)不需要。重復(fù)出現(xiàn)類型和軟件工程的關(guān)鍵原則產(chǎn)生沖突:應(yīng)該避免代碼重復(fù)。源碼中重復(fù)的代碼會(huì)增加編譯時(shí)間,導(dǎo)致對(duì)象代碼膨脹,并且通常會(huì)讓代碼庫(kù)更難運(yùn)行——這經(jīng)常引發(fā)不合邏輯的代碼,而不合邏輯的代碼庫(kù)一般會(huì)出現(xiàn)bug。除非是寫兩次比寫一個(gè)更有效果,不然誰(shuí)不喜歡少些點(diǎn)代碼嗎?


更偏愛(ài)使用make函數(shù)的第二個(gè)原因異常安全。假如我們有個(gè)函數(shù),根據(jù)優(yōu)先級(jí)來(lái)處理Widget:


void?processWidget(std::shared_ptrspw,?int?priority);

現(xiàn)在呢,假如我們有個(gè)計(jì)算優(yōu)先級(jí)的函數(shù),


int?computePriority();

然后我們用它和new創(chuàng)建的智能指針作為參數(shù)調(diào)用processWidget:


processWidget(std::shared_ptr(new?Widget),?
??????????????computePriority());????//?可能會(huì)資源泄漏

就如注釋所說(shuō),這代碼中new出來(lái)的Widget可能會(huì)泄漏,但是為什么?std::shared_ptr是為了防止資源泄漏而設(shè)計(jì)的,當(dāng)最后一個(gè)指向資源的std::shared_ptr對(duì)象消失,它們指向的資源也會(huì)被銷毀。如果每個(gè)人無(wú)論什么地方都使用std::shared_ptr,C++還有內(nèi)存泄漏這回事嗎?

答案是在編譯期間,源代碼轉(zhuǎn)換為目標(biāo)碼時(shí)(*.o文件)。在運(yùn)行時(shí)間,函數(shù)的參數(shù)在函數(shù)運(yùn)行前必須被求值,所以調(diào)用processWidget時(shí),下面的事請(qǐng)會(huì)在processWidget開始前執(zhí)行:

表達(dá)式“new Widget”會(huì)被求值,即,一個(gè)Widget對(duì)象必須在堆上被創(chuàng)建。std::shared_ptr的接收原生指針的構(gòu)造函數(shù)一定要執(zhí)行。computePriority一定要運(yùn)行。

編譯器在生成代碼時(shí)不會(huì)保證上面的執(zhí)行順序,“new Widget”一定會(huì)在std::shared_ptr構(gòu)造函數(shù)之前執(zhí)行,因?yàn)闃?gòu)造函數(shù)需要new的結(jié)果,但是computePriority可能在它們之前就被調(diào)用了,可能在它們之后,可能在它們之間。所以,編譯器生成代碼的執(zhí)行順序有可能是這樣的:

執(zhí)行“new Widget”。執(zhí)行computePriority。執(zhí)行std::shared_ptr的構(gòu)造函數(shù)。

如果生成的代碼真的是這樣,那么在運(yùn)行時(shí),computePriority產(chǎn)生了異常,步驟1中動(dòng)態(tài)分配的Widget就泄漏了,因?yàn)樗鼪](méi)有被步驟3中的std::shared_ptr保存。

使用std::make_shared_ptr可以避免這問(wèn)題。這樣調(diào)用代碼:


processWidget(std::make_shared(),?computePriority())

在運(yùn)行期間,std::make_shared和computePriority都有可能先被調(diào)用,如果先調(diào)用的是std::make_shared,那么指向動(dòng)態(tài)分配Widget對(duì)象的原生指針會(huì)安全地存儲(chǔ)在要返回的std::shared_ptr中,然后再調(diào)用computePriority。如果computePriority產(chǎn)出異常,std::shared_ptr的析構(gòu)函數(shù)就會(huì)銷毀持有的Widget。而如果先調(diào)用的是computePriority,并且產(chǎn)生異常,std::make_shared就不會(huì)被執(zhí)行,因此沒(méi)有動(dòng)態(tài)分配的Widget對(duì)象讓你擔(dān)心。

如果我們把std::shared_ptr和std::make_shared替換成std::unique_ptr和std::make_unique,效果一樣。使用std::make_unique替代new的重要性就像使用std::make_shared那樣:寫異常安全的代碼。


std::make_shared的一個(gè)特點(diǎn)(相比于直接使用new)是提高效率。使用std::make_shared允許編譯器生成更小、更快的代碼。考慮當(dāng)我們直接使用new時(shí):


std::shared_ptrspw(new?Widget);

很明顯這代碼涉及一次內(nèi)存分配,不過(guò),它實(shí)際上分配兩次。每個(gè)std::shared_ptr內(nèi)都含有一個(gè)指向控制塊的指針,這控制塊的內(nèi)存是由std::shared_ptr的構(gòu)造函數(shù)分配的,那么直接使用new,需要為Widget分配一次內(nèi)存,還需要為控制塊分配一次內(nèi)存。

如果用std::make_shared呢,


auto?spw?=?std::make_shared();

一次分配就夠了,因?yàn)閟td::make_shared會(huì)分配一大塊內(nèi)存來(lái)同時(shí)持有Widget對(duì)象和控制塊。這種優(yōu)化減少了程序的靜態(tài)尺寸,因?yàn)榇a只需要調(diào)用一次內(nèi)存分配函數(shù),然后它增加了代碼執(zhí)行的速度,因?yàn)橹恍枰峙湟淮蝺?nèi)存(說(shuō)明是分配內(nèi)存這個(gè)函數(shù)開銷略大)。而且,使用std::make_shared能避免了一些控制塊的簿記信息,潛在地減少了程序占用的內(nèi)存空間。

std::allocate_shared的性能分析和std::make_shared一樣,所以std::make_shared的性能優(yōu)勢(shì)也可以延伸到std::allocate_shared。


比起直接使用new,更偏愛(ài)使用make函數(shù),這個(gè)爭(zhēng)論是很熱烈的。雖有軟件工程、異常安全、性能優(yōu)勢(shì),不過(guò),本條款的指導(dǎo)方針是更偏愛(ài)使用make函數(shù),而不是單獨(dú)依賴它們,這是因?yàn)樵谀承顩r下它們不適用。

例如,沒(méi)有一個(gè)make函數(shù)可以指定自定義刪除器,但是std::unique_ptr和std::shared_ptr都有這樣的構(gòu)造函數(shù)。給定一個(gè)Widget的自定義刪除器,


auto?widgetDeleter?=?[](Widget*?pw)?{...}

我們可以直接使用new創(chuàng)建智能指針:


std::unique_ptrupw(new?Widget,?widgetDeleter);

std::shared_ptrspw(new?Widget,?widgetDeleter);

make函數(shù)就做不來(lái)這種事情。


make函數(shù)的第二個(gè)限制是來(lái)源于它們實(shí)現(xiàn)的句法細(xì)節(jié)。當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),如果該對(duì)象的重載構(gòu)造函數(shù)帶有std::initializer_list參數(shù),那么使用大括號(hào)創(chuàng)建對(duì)象會(huì)偏向于使用帶std::initializer_list構(gòu)造,要使用圓括號(hào)創(chuàng)建對(duì)象才能使用到非std::initializer_list構(gòu)造。make函數(shù)把它們的參數(shù)完美轉(zhuǎn)發(fā)給對(duì)象的構(gòu)造函數(shù),那么它們用的是大括號(hào)還是圓括號(hào)呢?對(duì)于某些類型,這問(wèn)題的答案的不同會(huì)導(dǎo)致結(jié)果有很大差異。例如,在這些調(diào)用中,


auto?upv?=?std::make_unique<std::vector>(10,?20);
auto?spv?=?std::make_shared<std::vector>(10,?20);

指針指向的是帶10個(gè)元素、每個(gè)值為20的std::vector呢,還是指向兩個(gè)元素、一個(gè)10、一個(gè)20的std::vector呢?還是說(shuō)結(jié)果不能確定嗎?

好消息是結(jié)果是能確定的:上面兩個(gè)都創(chuàng)建內(nèi)含10個(gè)值為20的std::vector。那意味著在make函數(shù)內(nèi),完美轉(zhuǎn)發(fā)使用的是圓括號(hào),而不是大括號(hào)。壞消息是如果你想用大括號(hào)初始化來(lái)構(gòu)造指向的對(duì)象,你只能直接使用new,如果你想使用make函數(shù),就要求完美轉(zhuǎn)發(fā)的能力支持大括號(hào)初始化,但是大括號(hào)初始化不能被完美轉(zhuǎn)發(fā)。不過(guò)也有一種能工作的方法:用auto推斷大括號(hào),從而創(chuàng)建一個(gè)std::initializer_list對(duì)象,然后把a(bǔ)uto變量傳遞給make函數(shù):


//?創(chuàng)建?std::initializer_list
auto?initList?=?{10,?20};

//?使用std::initializer_list構(gòu)造函數(shù)創(chuàng)建std::vector,容器中只有兩個(gè)元素
auto?spv?=?std::make_shared<std::vector>(initList);

對(duì)于std::unique_ptr,只有兩種情況(自定義刪除器和大括號(hào)初始化)會(huì)讓它的make函數(shù)出問(wèn)題。對(duì)于std::shared_ptr和它的make函數(shù),就多兩種情況,這兩種情況都是邊緣情況,不過(guò)一些開發(fā)者就喜歡住在邊緣,你可能就是他們中第一個(gè)。

一些類定義了自己的operator new和operator delete函數(shù),這些函數(shù)的出現(xiàn)暗示著常規(guī)的全局內(nèi)存分配和回收不適合這種類型的對(duì)象。通常情況下,設(shè)計(jì)這些函數(shù)只有為了精確分配和銷毀對(duì)象,例如,Widget對(duì)象的operator new和operator delete只有為了精確分配和回收大小為sizeof(Widget)的內(nèi)存塊才會(huì)設(shè)計(jì)。這兩個(gè)函數(shù)不適合std::shared_ptr的自定義分配(借助std::allocate_shared)和回收(借助自定義刪除器),因?yàn)閟td::allocate_shared請(qǐng)求內(nèi)存的大小不是對(duì)象的尺寸,而是對(duì)象尺寸加上控制塊尺寸。結(jié)果就是,使用make函數(shù)為那些——定義自己版本的operator new和operator delete的——類創(chuàng)建對(duì)象是個(gè)糟糕的想法。


比起直接使用new,std::make_shared的占用內(nèi)存大小和速度優(yōu)勢(shì)來(lái)源于:std::shared_ptr的控制塊與它管理的對(duì)象放在同一塊內(nèi)存。當(dāng)引用計(jì)數(shù)為0時(shí),對(duì)象被銷毀(即調(diào)用了析構(gòu)函數(shù)),但是,它使用的內(nèi)存不會(huì)釋放,除非控制塊也被銷毀,因?yàn)閷?duì)象和控制塊在同一塊動(dòng)態(tài)分配的內(nèi)存上。

就像我提起那樣,控制塊上除了引用計(jì)數(shù)還有別的薄記信息。引用計(jì)數(shù)記錄的是有多少std::shared_ptr指向控制塊,但是控制塊還有第二種引用計(jì)數(shù),記錄有多少std::weak_ptr指向控制塊。這種引用計(jì)數(shù)稱為weak count。當(dāng)std::weak_ptr檢查它是否過(guò)期時(shí)(expired),它通過(guò)檢查控制塊中的引用計(jì)數(shù)(不是weak count)來(lái)實(shí)現(xiàn)。如果引用計(jì)數(shù)為0(即沒(méi)有std::shared_ptr指向這個(gè)對(duì)象,因此被銷毀),std::weak_ptr就過(guò)期,否則就沒(méi)有過(guò)期。

但是,只要有std::weak_ptr指向控制塊(weak count大于0),控制塊就必須繼續(xù)存在,而只要控制塊存在,容納它的內(nèi)存塊也依舊存在。那么,通過(guò)make函數(shù)創(chuàng)建對(duì)象分配的內(nèi)存,要直到最后一個(gè)指向它的std::shared_ptr和std::weak_ptr對(duì)象銷毀,才能被回收。

如果對(duì)象的類型非常大,并且最后一個(gè)std::shared_ptr銷毀和最后一個(gè)std::weak_ptr銷毀之間的時(shí)間間隔很大,那么是對(duì)象銷毀和內(nèi)存被回收之間的會(huì)有延遲:


class?ReallyBigType?{?...?};

auto?pBigObj?=??????????????????????????//?借助std::make_shared
???std::make_shared();???//?創(chuàng)建類型非常大的對(duì)象
...???????????????//?創(chuàng)建std::shared_ptr和std::weak_ptr指向?qū)ο?
...???????????????//?最后一個(gè)std::shared_ptr被銷毀,那仍有std::weak_ptr存在
...???????????????//?在這個(gè)期間,之前類型非常大的對(duì)象使用的內(nèi)存仍然被占用
...???????????????//?最后一個(gè)std::weak被銷毀,控制塊和對(duì)象共占的內(nèi)存被釋放

如果直接使用new,ReallyBigType對(duì)象的內(nèi)存只要在最后一個(gè)std::shared_ptr被銷毀就能被釋放:


class?ReallyBigType?{?...?};

auto?pBigObj?=??????????????????????????//?借助std::make_shared
???std::make_shared();???//?創(chuàng)建類型非常大的對(duì)象
...???????????????//?創(chuàng)建std::shared_ptr和std::weak_ptr指向?qū)ο?
...???????????????//?最后一個(gè)std::shared_ptr被銷毀,那仍有std::weak_ptr存在
...???????????????//?在這個(gè)期間,之前類型非常大的對(duì)象使用的內(nèi)存仍然被占用
...???????????????//?最后一個(gè)std::weak被銷毀,控制塊和對(duì)象共占的內(nèi)存被釋放

當(dāng)你發(fā)現(xiàn)某些情況不能使用或者不適合使用std::make_shared,卻又想要防止容易發(fā)生的異常安全問(wèn)題。最好的辦法就是確保當(dāng)你直接使用new時(shí),用一條語(yǔ)句執(zhí)行——把new的結(jié)果馬上傳遞給智能指針的構(gòu)造函數(shù),并且該語(yǔ)句就做這一件事。這防止編譯器生成new和std::shared_ptr構(gòu)造之間發(fā)出異常。

作為例子,我們修改之前的異常不安全processWidget,并指定自定義刪除器:


void?processWidget(std::shared_ptrspw,?int?priority);?//?如前
void?cusDel(Widget?*ptr);??????//??自定義刪除器

這里是異常不安全的調(diào)用:


processWidget(???????????//?如前,可能資源泄漏
???std::shared_ptr(new?Widget,?cusDel),
???computePriority()
);

回憶:如果computePriority調(diào)用在“new Widget”之前,std::shared_ptr構(gòu)造之后,然后computePriority產(chǎn)生異常,那么動(dòng)態(tài)分配的Widget就會(huì)泄漏。

這里要使用自定義刪除器,不能使用std::make_shared,所以避免泄漏的方法就是把分配Widget和std::shared_ptr構(gòu)造放在只屬于它們的語(yǔ)句,然后再用std::shared_ptr的結(jié)果調(diào)用processWidget。這是這項(xiàng)技術(shù)的本質(zhì)部分,等下我們可見到,我們可以修改它從而提高性能:


std::shared_ptrspw(new?Widget,?cusDel);
processWidget(spw,?computeWidget);??//?正確,但沒(méi)有優(yōu)化,看下面

這代碼是可行的,因?yàn)閟td::shared_ptr得到了原生指針的所有權(quán),盡管構(gòu)造函數(shù)可能發(fā)出異常。在這個(gè)例子中,如果spw的構(gòu)造期間拋出異常(例如,由于不能為控制塊動(dòng)態(tài)分配內(nèi)存),也能保證cusDel被調(diào)用(以“new Widget”的結(jié)果為參數(shù))。

有個(gè)小小的性能問(wèn)題,在異常不安全的調(diào)用中,我們傳給processWidget的是一個(gè)右值,


processWidget(
???std::shared_ptr(new?Widget,?cusDel),??//?參數(shù)是右值
???computePriority()
);

但是在異常安全的調(diào)用中,我們傳遞的是個(gè)左值:


processWidget(spw,?computePriority());???//?參數(shù)是左值

因?yàn)閜rocessWidget的std::shared_ptr參數(shù)是值傳遞,從一個(gè)右值構(gòu)造使用的是移動(dòng),從一個(gè)左值構(gòu)造使用的是拷貝。對(duì)于std::shared_ptr,這差別挺大的,因?yàn)榭截愐粋€(gè)std::shared_ptr需要增加它的引用計(jì)數(shù),這是原子操作,而移動(dòng)操作完全不用操作引用計(jì)數(shù)。針對(duì)于異常安全代碼想要達(dá)到異常不安全代碼的性能水平,我們需要使用std::move來(lái)把spw轉(zhuǎn)化為右值:


processWidget(std::move(spw),?computePriority());??//?現(xiàn)在也一樣高效

這是有趣的而且值得知道,但是通常也是不相干的,因?yàn)槟愫苌儆欣碛刹挥胢ake函數(shù),除非你有迫不得已的理由,否則,你應(yīng)該使用make函數(shù)。

總結(jié)

需要記住的3點(diǎn):

相比于直接使用new,make函數(shù)可以消除代碼重復(fù),提高異常安全,而且std::make_shared和std::allocate_shared生成的代碼更小更快。不適合使用make函數(shù)的場(chǎng)合包括需要指定自定義刪除器和想要傳遞大括號(hào)初始值。對(duì)于std::shared_ptr,使用make函數(shù)可能是不明智的額外場(chǎng)合包括(1)自定義內(nèi)存管理函數(shù)的類和(2)內(nèi)存緊張的系統(tǒng)中,有非常大的對(duì)象,然后std::weak_ptr比std::shared_ptr長(zhǎng)壽。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉