新聞中心
最近因?yàn)轫?xiàng)目要求用c++,之前一直很討厭c++,沒(méi)辦法只能短時(shí)間彌補(bǔ)c++的知識(shí),項(xiàng)目中需要定義一個(gè)函數(shù)指針類型的vector,本以為很簡(jiǎn)單的問(wèn)題,結(jié)果調(diào)試了一天,才發(fā)現(xiàn)錯(cuò)在哪里。

成都創(chuàng)新互聯(lián)始終致力于在企業(yè)網(wǎng)站建設(shè)領(lǐng)域發(fā)展。秉承“創(chuàng)新、求實(shí)、誠(chéng)信、拼搏”的企業(yè)精神,致力為企業(yè)提供全面的網(wǎng)絡(luò)宣傳與技術(shù)應(yīng)用整體策劃方案,為企業(yè)提供包括“網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、微信網(wǎng)站建設(shè)、微信小程序開(kāi)發(fā)、商城網(wǎng)站定制開(kāi)發(fā)、平臺(tái)網(wǎng)站建設(shè)秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
多余的std::function
先上代碼吧,這里有一個(gè)測(cè)試代碼,為什么要有測(cè)試代碼?是因?yàn)橄旅娴姆绞轿以谧铋_(kāi)始驗(yàn)證該種實(shí)現(xiàn)時(shí)打印的地址是對(duì)的,但是之后一段時(shí)間就不對(duì)了,所以摘出來(lái)寫(xiě)了一個(gè)測(cè)試代碼。
代碼非常簡(jiǎn)單:使用using std::function的方式定義一個(gè)函數(shù)指針類型func_t,然后實(shí)現(xiàn)三個(gè)print函數(shù),在main函數(shù)中定義一個(gè)vector存放三個(gè)函數(shù)的地址,打印三個(gè)函數(shù)的實(shí)際地址,之后遍歷vector打印存放的元素值。
#include
#include
#include
// 定義 std::function 類型的函數(shù)指針別名
using func_t = std::function;
// 示例函數(shù)
void print(int x, void* y, size_t a, size_t b, void* c) {
std::cout << "print hello\n";
}
void print1(int x, void* y, size_t a, size_t b, void* c) {
std::cout << "print1 hello\n";
}
void print2(int x, void* y, size_t a, size_t b, void* c) {
std::cout << "print2 hello\n";
}
int main() {
// 創(chuàng)建一個(gè)存儲(chǔ) std::function 類型的函數(shù)指針對(duì)象的 std::vector
std::vector vec;
// 使用 push_back 將函數(shù)指針對(duì)象添加到 std::vector 中
vec.push_back(print);
vec.push_back(print1);
vec.push_back(print2);
printf("%x, %x, %x\n", print, print1, print2);
// 遍歷 std::vector 并依次調(diào)用存儲(chǔ)的函數(shù)指針對(duì)象
for (const auto& func : vec) {
// 調(diào)用函數(shù)指針對(duì)象
//func(0, nullptr, 0, 0, nullptr);
printf("%x.\n", func);
}
return 0;
} 執(zhí)行后的結(jié)果:
我最開(kāi)始的理解是vector內(nèi)部存放的地址就是三個(gè)函數(shù)的地址。結(jié)果打印的結(jié)果意料之外啊,居然一樣,我嘗試在for循環(huán)遍歷時(shí)執(zhí)行該地址函數(shù),結(jié)果還能正常運(yùn)行。最開(kāi)始以為是vector遍歷取值的問(wèn)題,后來(lái)經(jīng)過(guò)一番驗(yàn)證沒(méi)問(wèn)題,最后鎖定要函數(shù)指針定義上。
我嘗試切換一種函數(shù)指針定義,使用我最原始的方式:
// 定義 std::function 類型的函數(shù)指針別名
//using func_t = std::function;
using func_t = void (*)(int, void*, size_t, size_t, void*); 運(yùn)行后發(fā)現(xiàn)這次是對(duì)的了:
最后經(jīng)過(guò)一番查找,得出結(jié)論如下:
實(shí)際上,std::function 存儲(chǔ)函數(shù)指針時(shí),不直接存儲(chǔ)函數(shù)指針本身的地址,而是存儲(chǔ)了函數(shù)指針對(duì)象的一些信息,因此直接使用 %x 來(lái)打印 std::function 存儲(chǔ)的函數(shù)指針可能無(wú)法獲得正確的地址。
在標(biāo)準(zhǔn)庫(kù) 中,std::function 是一個(gè)函數(shù)包裝器,它可以包含各種可調(diào)用對(duì)象(函數(shù)指針、函數(shù)對(duì)象、成員函數(shù)指針、Lambda 表達(dá)式等)。因此,std::function 內(nèi)部存儲(chǔ)了被包裝對(duì)象的地址以及其他信息,而不是直接將被包裝對(duì)象的地址暴露給用戶。
由于 std::function 對(duì)象的內(nèi)部結(jié)構(gòu)不同于原始函數(shù)指針, std::function 對(duì)象存儲(chǔ)了更多的信息,所以直接打印 std::function 對(duì)象的地址并不會(huì)得到和原始函數(shù)指針相同的值,打印它的地址并不等同于打印函數(shù)指針的地址。
所以,如果需要存儲(chǔ)函數(shù)指針并在之后通過(guò) std::function 來(lái)調(diào)用它們,可以直接通過(guò) std::function 來(lái)調(diào)用并且可以得到預(yù)期的結(jié)果,但是打印地址是不保證能夠得到和原始函數(shù)指針相同的地址(這也是我遇到了幾次和原始函數(shù)指針一致的時(shí)候,這也是造成我更迷茫的原因)。
那為什么打印的值一樣呢?
因?yàn)樵诒闅v std::vector
總結(jié)
如果你也需要直接獲取存儲(chǔ)的函數(shù)指針的地址(C語(yǔ)言的習(xí)慣),最好還是直接使用原始的函數(shù)指針,而不是通過(guò) std::function 來(lái)存儲(chǔ)和獲取函數(shù)指針的地址。
名稱欄目:讓人壓抑的 C++:記一個(gè)函數(shù)指針的問(wèn)題
文章轉(zhuǎn)載:http://www.dlmjj.cn/article/djocsis.html


咨詢
建站咨詢
