簡體   English   中英

std :: function的奇怪行為

[英]Strange behavior with std::function

我正在使用C ++ 11庫中的標准函數包裝器,我看到它的布爾運算符有一些奇怪的行為。 如果我創建一個std::function對象,則布爾運算符返回false。 如果我將nullptr分配給對象並再次檢查,則仍然如此。 當我為它分配一個我已經轉換為函數指針的void指針時出現問題。 考慮以下程序:

#include <functional>
#include <iostream>

void* Test() {
    return nullptr;
}

int main(int argc, char* argv[]) {
    std::function<void()> foo;
    std::cout << !!foo << std::endl;

    foo = nullptr;
    std::cout << !!foo << std::endl;

    foo = reinterpret_cast<void(*)()>(Test());
    std::cout << !!foo << std::endl;

    return 0;
}

我期望輸出為0 0 0但結果是0 0 1 (見演示 )。 任何人都可以解釋為什么布爾運算符在包含空的,不可調用的函數指針時返回true? 還請提一下在std::function檢查nullptr的解決方法

注意:我已經嘗試檢查目標是否為null(使用foo.target<void*>() == nullptr )而不是使用布爾運算符,但似乎無論函數對象包含什么,目標始終為null(即使函數對象被調用完全正常)。

對我來說看起來像個錯誤。 首先,這是一個簡單的例子 ,不播放任何帶有強制轉換的游戲:

#include <functional>
#include <iostream>

typedef void (*VF)();

VF Test() {
    return nullptr;
}

int main(int argc, char* argv[]) {
    std::function<void()> foo(Test());
    std::cout << !!foo << std::endl;
    return 0;
}

它仍然用GCC打印1。 它不應該:

20.8.11.2.1
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 要求: F應為CopyConstructible 對於參數類型ArgTypesf應為Callable (20.8.11.2)並返回類型R 的拷貝構造函數和析構函數A不拋出異常。
8 后置條件: !*this如果滿足以下任何條件:

  • f是一個NULL函數指針。
  • f是指向成員的NULL指針。
  • F是函數類模板的實例,並且!f

我不認為代碼正在做你認為它做的事情。 這一行:

foo = reinterpret_cast<void(*)()>(Test());

表示您從Test()收到void* 然后,您繼續將此指針指向對象 reinterpret_cast指向函數指針 這是不允許的,因此代碼會產生未定義的行為,因此編譯器的任何輸出都是有效的。

標准的相關部分是

5.2.10重新解釋強制轉換[expr.reinterpret.cast]

8有條件地支持將函數指針轉換為對象指針類型,反之亦然。 這種轉換的含義是實現定義的,除非實現支持兩個方向的轉換,將一種類型的prvalue轉換為另一種類型並返回,可能具有不同的cv-限定條件,將產生原始指針值。

9空指針值(4.10)將轉換為目標類型的空指針值。 [ 注意: std::nullptr_t類型的空指針常量不能轉換為指針類型,並且整數類型的空指針常量不一定轉換為空指針值。 - 結束說明 ]

4.10指針轉換[conv.ptr]

1 空指針常量是整數類型的整數常量表達式(5.19)prvalue,其計算結果為零或類型為std::nullptr_t 空指針常量可以轉換為指針類型; 結果是該類型空指針值 並且可以與對象指針或函數指針類型的每個其他值區分開

(強調我的)

這是一個簡化的測試用例,將std::function (及其可能的錯誤)排除在等式之外:

#include <iostream>

int main() {
    using fp_t = void(*)();
    void* vn = nullptr;
    fp_t foo = reinterpret_cast<fp_t>(vn); // GCC: warning, Clang: silence
    //fp_t foo = reinterpret_cast<fp_t>(nullptr); // error (GCC and Clang!)
    std::cout << !!foo << std::endl;
}

實例

暫無
暫無

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

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