2012-12-28 139 views
1

我試圖使用std::unique_ptr爲了將整數句柄存儲到一些不透明的對象。爲此,我已經定義了一個自定義刪除類型,它的作用是將typedef int pointer覆蓋原始指針類型爲int而不是int*。這個過程在這個網站的最後一節中描述:http://asawicki.info/news_1494_unique_ptr_in_visual_c_2010.html在GCC 4.7.2中破壞std :: unique_ptr

下面是一些示例代碼,以更好地說明什麼,我試圖做的:

#include <memory> 
#include <iostream> 

static void close(int p) 
{ 
    std::cout << p << " has been deleted!" << std::endl; 
} 

struct handle_deleter 
{ 
    typedef int pointer; 
    void operator()(pointer p) { close(p); } 
}; 

typedef std::unique_ptr< int, handle_deleter> unique_handle; 

int main(int argc, char *argv[]) 
{ 
    unique_handle handle(1); 

    return 0; 
} 

當我編譯使用GCC 4.7.2本規範,我得到以下錯誤:

In file included from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/memory:86:0, 
       from unique_ptr_test.cpp:1: 
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/unique_ptr.h: In instantiation of ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = int; _Dp = handle_deleter]’: 
unique_ptr_test.cpp:19:23: required from here 
/usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/unique_ptr.h:172:2: error: invalid operands of types ‘int’ and ‘std::nullptr_t’ to binary ‘operator!=’ 

~unique_ptr程序的代碼如下:

// Destructor. 
~unique_ptr() noexcept 
{ 
    auto& __ptr = std::get<0>(_M_t); 
    if (__ptr != nullptr) 
     get_deleter()(__ptr); 
    __ptr = pointer(); 
} 

根據我的說法,針對nullptr的檢查沒有意義,因爲原始指針類型爲int(而不是int*,因爲在HandleDeleter中將其重寫)。奇怪的是,這個代碼在GCC 4.6.1下編譯沒有錯誤。執行時,樣本顯示「1已被刪除!」如預期。

我想知道是否有任何細節,我忽略或如果它真的是GCC的STL實現unique_ptr內的錯誤。

感謝,

PMJ

+11

臨提示:第一次搜索的某些語義在一個表,其中列出*你的*代碼/理解錯誤,並且不會立即責怪實施被「破壞」。現在,'Deleter :: pointer'必須滿足* Nullable Pointer *要求。這包括比較'nullptr',因爲'std :: unique_ptr'被指定爲只在get()!= nullptr'時調用deleter。 IOW,你只需要包裝你的'int'並將其用作'pointer'類型。 – Xeo

+1

'std :: unique_ptr '表示指向T *的*指針。沒有辦法讓'std :: unique_ptr :: pointer'是'int'。換句話說,您忘記了應用於第一個模板參數的隱式星號。 – GManNickG

+1

@Xeo:爲什麼不是一個答案! :-) –

回答

7

正如我在我的評論說,如果你通過刪除器類型有一個嵌套pointer類型定義,它必須滿足NullablePointer要求:

20.7.1.2 [unique.ptr.single] p3

If the type remove_reference<D>::type::pointer exists, then unique_ptr<T, D>::pointer shall be a synonym for remove_reference<D>::type::pointer . Otherwise unique_ptr<T, D>::pointer shall be a synonym for T* . The type unique_ptr<T, D>::pointer shall satisfy the requirements of NullablePointer (17.6.3.3).

§17.6.3.3然後列出類型必須滿足的所有需求都是NullablePointer。

u denotes an identifier, t denotes a non-const lvalue of type P , a and b denote values of type (possibly const) P , and np denotes a value of type (possibly const) std::nullptr_t .

Expression Return type       Operational semantics 
P u(np);           post: u == nullptr 
P u = np; 
P(np)            post: P(np) == nullptr 
t = np  P&         post: t == nullptr 
a != b  contextually convertible to bool !(a == b) 
a == np  contextually convertible to bool a == P() 
np == a 
a != np  contextually convertible to bool !(a == np) 
np != a 

現在,最簡單的辦法是在提供這些語義的類型來包裝你int

#include <cstddef> // std::nullptr_t 

struct handle{ 
    handle() : value(0){} 
    handle(std::nullptr_t) : value(0){} 
    /*explicit*/ handle(int v) : value(v){} // make it explicit if you need it 
    // special members can be generated 

    handle& operator=(std::nullptr_t){ value = 0; return *this; } 

    // contextual conversion to bool 
    explicit operator bool() const{ return value != 0; } 

    int value; 
}; 

bool operator==(handle lhs, handle rhs){ return lhs.value == rhs.value; } 
bool operator!=(handle lhs, handle rhs){ return lhs.value != rhs.value; } 
// comparision against 'nullptr' is handled by the above operators 
// since 'nullptr' can be implicitly converted to 'handle' 
+0

請注意,如果'0'對於句柄而言是一個有意義的值,那麼您可能希望專門處理與'nullptr'的比較。或者,如果您有任何無意義的值,請在'nullptr'構造函數中將'value'設置爲該值。 – Xeo

+0

謝謝您的深入解釋。現在,我可以清楚地看到爲什麼這種方法是錯誤的。我想我可以通過使用(強制)'std :: unique_ptr'來存儲整數句柄來保存一些工作。畢竟,從頭開始實現unique_handle可能會更容易。 :) – pmjobin