2010-03-02 21 views
3

我目前正在嘗試使用Howard Hinnant's unique_ptr implementation,並且遇到編譯錯誤。下面是一些示例代碼:在這種情況下,Hinnant的unique_ptr實現是否錯誤地將派生對象轉換爲基類?

struct Base {}; 

struct Derived : public Base {}; 

void testfun(boost::unique_ptr<Base>); 

void test() 
{ 
    unique_ptr<Derived> testDerived; 
    unique_ptr<Base> testBase(move(testDerived)); // ok, construct base explicitly from derived 
    testfun(move(testBase));      // ok, pass base to testfun which expects base 
    testfun(unique_ptr<Base>(move(testDerived))); // ok, explicitly converts to unique_ptr<Base> 
    testfun(move(testDerived));     // error on this line 
} 

我得到的錯誤是

In function 'void test()': 
error: no matching function for call to 'boost::unique_ptr<Base, boost::default_delete<Base> >::unique_ptr(boost::unique_ptr<Base, boost::default_delete<Base> >)' 
note: candidates are: boost::unique_ptr<T, D>::unique_ptr(boost::detail_unique_ptr::rv<boost::unique_ptr<T, D> >) [with T = Base, D = boost::default_delete<Base>] 
note:     boost::unique_ptr<T, D>::unique_ptr(boost::unique_ptr<T, D>&) [with T = Base, D = boost::default_delete<Base>] 
error: initializing argument 1 of 'void testfun(boost::unique_ptr<Base, boost::default_delete<Base> >)' from result of 'boost::unique_ptr<T, D>::unique_ptr(boost::unique_ptr<U, E>, typename boost::enable_if_c<((((! boost::is_array<U>::value) && boost::detail_unique_ptr::is_convertible<typename boost::unique_ptr<U, boost::default_delete<U> >::pointer,typename boost::detail_unique_ptr::pointer_type<T, D>::type>::value) && boost::detail_unique_ptr::is_convertible<E,D>::value) && ((! boost::is_reference<D>::value) || boost::is_same<D,E>::value)), void>::type*) [with U = Derived, E = boost::default_delete<Derived>, T = Base, D = boost::default_delete<Base>]' 

這似乎是有問題的行應該不會失敗。這是實現中的一個錯誤,由於缺少C++ 0x語言特性而導致實現受到限制,或者是對unique_ptrs規則的誤解?

(注意,我知道,因爲我動了同樣的事情不止一次這將不會在運行時正常工作;我只是想弄清楚編譯時錯誤。)

+1

大概描述的關鍵部分是「這個仿真的目的捕獲** C++ 0X unique_ptr的大部分行爲**「。我認爲這意味着並非所有的行爲都在那裏。 – 2010-03-02 20:05:53

+0

以下是導致C++ 03的這種行爲的論文:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf – 2010-03-02 20:40:12

回答

0

進一步的研究使我this note,導致我相信,這是實現的已知限制:

測試的3目前失敗,我(不能在編譯時, 應該編譯,運行並通過)。這些都與[unique.ptr.single.ctor]中指定的 轉換構造函數相關聯。當 源和目標是不同類型的,這個仿真要求 的轉換是明確的,並拒絕編譯隱 轉換:

unique_ptr<base> b(unique_ptr<derived>()); // ok 

unique_ptr<base> b = unique_ptr<derived>(); // causes 3 compile time failures under unique.ptr/unique.ptr.single/unique.ptr.single.ctor . 
+0

litb的書寫內容非常豐富,但我認爲這是對這個問題的更直接的回答。兩者都應該被有興趣的人閱讀:-) – SCFrench 2010-03-17 14:24:01

1

對於一個類似的例子,請參閱本應該失敗過

unique_ptr<Base> testBase = move(testDerived); 

這裏的問題是,此舉語義是如何實現的:在「拷貝構造函數」需要一個非const引用,因此是不能夠綁定到臨時工。至尚「搬家」,從臨時工,班裏有一個轉換功能(下面是真的只是概念上的 - 他們可以在細節上有不同的實現):

operator rv<T>() { return rv<T>(*this); } 

和構造函數將採取對象:

unique_ptr(rv<T> r):ptr_(r.release()) { } 

這裏是出於同樣的原因失敗的例子:

// move helper. rv<> in unique_ptr 
struct E { }; 

// simulates a unique_ptr<D> 
struct D { }; 

// simulates the unique_ptr<B> 
struct A { 
    A() { } 

    // accepts "derived" classes. Note that for unique_ptr, this will need that 
    // the argument needs to be copied (we have a by-value parameter). Thus we 
    // automatically ensure only rvalue derived-class pointers are accepted. 
    A(D) { } 

    // these will accept rvalues 
    A(E) { } 
    operator E() { return E(); } 

private: 
    A(A&); // private, error if passed lvalue 
}; 

現在,考慮下面的代碼:

// allowed: goes: D -> A(D) 
A a((D())); 

// compile failure. Goes: 
// D -> A(D) -> A(E) 
A a = D(); 

複製初始化將首先轉換爲A。但是,暫時的A對象被試圖再次複製到最終對象。這將需要使用operator E的方式。但是,這是在初始化另一用戶定義的轉換,其中所述標準禁止:

13.3.3.1/4

在類複製初始化的第二步驟中調用的所述臨時的複製,[...] ,只允許使用標準轉換序列和省略號轉換序列。

這就是爲什麼你的代碼失敗。

相關問題