簡體   English   中英

dynamic_cast的性能

[英]Performance of dynamic_cast

我之前問了一個問題為什么dynamic_cast是邪惡的? 答案讓我寫了一些關於dynamic_cast性能的代碼如下。我編譯和測試, dynamic_cast消耗的時間比沒有dynamic_cast的時間略大。我沒有看到dynamic_cast的證據是耗時的。我寫的正確的代碼?

代碼是:

class Animal
{
public:
    virtual ~Animal(){};
};

class Cat : public Animal
{
public:
    std::string param1;
    std::string param2;
    std::string param3;
    std::string param4;
    std::string param5;
    int param6;
    int param7;
};

bool _process(Cat* cat)
{
    cat->param1 = "abcde";
    cat->param2 = "abcde";
    cat->param3 = "abcde";
    cat->param4 = "abcde";
    cat->param5 = "abcde";
    cat->param6 = 1;
    cat->param7 = 2;
    return true;
}

bool process(Animal *ptr)
{
    Cat *cat = dynamic_cast<Cat*>(ptr);
    if (cat == NULL)
    {
        return false;
    } 
    _process(cat);
    return true;
}
int main(int argc, char* argv[])
{
    /*
    argv[1] : object num
    */

    if (argc != 2)
    {
        std::cout << "Error: invalid argc " << std::endl;
        return -1;
    }

    int obj_num = atoi(argv[1]);
    if (obj_num <= 0)
    {
        std::cout << "Error: object num" << std::endl;
    }

    int c = 0;
    for (; c < obj_num; c++)
    {
        Cat cat;
        #ifdef _USE_CAST
        if (!process(&cat))
        {
            std::cout << "Error: failed to process " << std::endl;
            return -3;
        }
        #else
        if (!_process(&cat))
        {
            std::cout << "Error: failed to process " << std::endl;
            return -3;
        }

        #endif
    }

    return 0;
}

使用以下方法編譯

g++ -D_USE_CAST -o dynamic_cast_test  dynamic_cast_benchmark.c
g++ -o dynamic_cast_no_test dynamic_cast_benchmark.c

使用num執行它們,即1,10,100 ...:

$time ./dynamic_cast_test num
$time ./dynamic_cast_no_test num

結果:

                 dynamic_cast               non_dynamic_cast
num  10,000   
                real    0m0.010s            real    0m0.008s
                user    0m0.006s            user    0m0.006s
                sys     0m0.001s            sys     0m0.001s

     100,000 
                real    0m0.059s            real    0m0.056s
                user    0m0.054s            user    0m0.054s
                sys     0m0.001s            sys     0m0.001s

     1,000,000
                real    0m0.523s            real    0m0.519s
                user    0m0.517s            user    0m0.511s
                sys     0m0.001s            sys     0m0.004s

     10,000,000
                real    0m6.050s            real    0m5.126s
                user    0m5.641s            user    0m4.986s
                sys     0m0.036s            sys     0m0.019s

     100,000,000
                real    0m52.962s           real    0m51.178s
                user    0m51.697s           user    0m50.226s
                sys     0m0.173s            sys     0m0.092s

硬件和操作系統:

OS:Linux
CPU:Intel(R) Xeon(R) CPU E5607  @ 2.27GHz  (4 cores)

你確實寫了正確的代碼,雖然我不會將類型硬編碼為Cat。 你可以,只是為了安全起見,使用命令行參數來決定是否建造一只貓或狗,(你也應該實施)。 嘗試禁用優化,以查看它是否發揮了重要作用。

最后,要謹慎一點。 分析並不像在計算機上進行測量那么簡單,因此您必須意識到您所做的只是帶您到目前為止。 它確實給了你一個想法,不要以為你得到任何包羅萬象的答案。

我會改編我的帖子。

你的代碼是正確的,它編譯得很好。

由於虛方法和dynamic_cast運算符是相關問題,請從wiki檢查此信息,希望它有用。

維基:

與非虛擬調用相比,虛擬調用至少需要額外的索引取消引用,有時需要“修正”添加,這只是跳轉到編譯指針。 因此,調用虛函數本質上比調用非虛函數慢。 1996年進行的一項實驗表明,大約6-13%的執行時間花在簡單調度到正確的功能上,盡管開銷可能高達50%。[4] 由於更大的高速緩存和更好的分支預測,虛擬功能的成本在現代CPU架構上可能不會那么高。

此外,在未使用JIT編譯的環境中,通常無法內聯虛函數調用。 雖然編譯器可以用例如每個內聯體的條件執行來替換查找和間接調用,但這種優化並不常見。

為了避免這種開銷,編譯器通常會避免在編譯時解析調用時使用vtable。

因此,對上面的f1的調用可能不需要vtable查找,因為編譯器可能能夠告訴d此時只能保持D,並且D不會覆蓋f1。 或者編譯器(或優化器)可能能夠檢測到程序中任何地方都沒有B1的子類來覆蓋f1。 對B1 :: f1或B2 :: f2的調用可能不需要vtable查找,因為實現是明確指定的(盡管它仍然需要'this'指針修復)。

另外,正如您可能知道的,當您在類中聲明虛方法時,依賴於實現但幾乎總是如此,您的編譯器將隱式地將虛方法表添加為您的類的新方法,因此該類的每​​個實例將占用更多的內存空間,在沒有它的情況下在類上嘗試sizeof。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM