2017-09-14 104 views
2
#include <memory> 

template <typename T> 
class Wrapper { 
public: 
    Wrapper() = delete; 
    Wrapper(const Wrapper&) = delete; 
    Wrapper(Wrapper&&) = delete; 

    ~Wrapper() = default; 

    Wrapper(const T&) = delete; 
    Wrapper(T&& in) : instance{std::move(in)} {} 

    T instance; 
}; 

void foo(Wrapper<std::shared_ptr<int>>) {} 

int main() { 
    auto ptr = std::make_shared<int>(1); 
    foo(std::move(ptr)); 
} 

這一直致力於在C++ 17所以我從來沒有給它認爲,但爲什麼會發生這種代碼嘗試和調用在C++ 14的移動構造函數?它不應該在函數參數中構建嗎?這看起來不是C++ 17的問題,但不是用C++ 14編譯的。複製參數調用構造函數刪除時構造不應該叫

我看到的唯一解決方法是使foo參數爲右值,但是有什麼我可以做的,使得這項工作不需要在foo中使參數在C++ 14中成爲一個右值?


我首先想到的會是暫時的必須是構造函數才能被傳遞給函數,但什麼是更令人驚訝的是,即使-fno-elide-constructors和取消刪除移動構造函數和拷貝構造函數那些不似乎被稱爲!這是gcc和clang中的一個bug嗎?

的錯誤 見https://wandbox.org/permlink/f6sa5Rm3NxZLy5P1,看看奇怪的行爲https://wandbox.org/permlink/Kh6CG4OVbUAjvEZz

+1

什麼是確切的錯誤,你會得到 – vu1p3n0x

+0

@ vu1p3n0x張貼他們的問題,它是在標題以及 – Curious

+1

在你的鏈接,「看到了奇怪的行爲,」它確實呼叫轉移構造 –

回答

4

當你調用foo(std::move(ptr));你不給它一個Wrapper<std::shared_ptr<int>>。因此,編譯器會生成一個臨時文件並使用它來構造foo的參數。現在,這可以被忽略,我們可以直接構造一個Wrapper<std::shared_ptr<int>>,但移動/複製構造函數仍然需要可訪問,即使它從不被調用。

隨着C++ 17的不再發生。我們有guaranteed copy elision這意味着沒有臨時實現,而是直接構造參數。

+0

但爲什麼移動構造函數從來沒有調用?即使使用'-fno-elide-constructors' – Curious

+0

@語言所需的複雜構造函數,但可以通過優化來消除調用。 – Slava

+0

@Curious因爲即使編譯器足夠聰明以至於暫時不符合語言標準,仍然可以訪問相應的構造函數。 – NathanOliver