2017-10-11 86 views
0

參照以下代碼,我不明白爲什麼move constructor被稱爲lvaluervalue。我希望copy ctor打印時,我通過lvaluepush方法。正向參照混淆

#include <iostream> 
#include <string> 
#include <vector> 
using namespace std; 

class my_obj 
{ 
public: 
    my_obj() 
    { 
     cout << "default ctor\n"; 
    } 

    my_obj(const my_obj& other) 
    { 
     cout << "copy ctor\n"; 
    } 

    my_obj(my_obj&& other) 
    { 
     cout << "move ctor\n"; 
    }  
}; 

class test 
{ 
public: 
    template<typename T> 
    void push(T&& object) 
    { 
     print(forward<T>(object)); 
    } 

    template<typename T> 
    void print(T&& a) 
    { 
     cout << "move\n"; 
     my_obj temp = forward<T>(a); 
    } 

    template<typename T> 
    void print(T& a) 
    { 
     cout << "val\n"; 
     my_obj temp = forward<T>(a); 
    } 
}; 


int main() 
{ 
    my_obj obj; 
    test f; 

    f.push(obj); // why is move ctor called here? shouldnt it be copy ctor since not rvalue 
    cout << "\nPUSHING TEMP\n\n"; 
    f.push(my_obj {}); 
} 

輸出:

default ctor 
val 
move ctor 

PUSHING TEMP 

default ctor 
move 
move ctor 

回答

4

在這裏:

template<typename T> 
void print(T& a) 
{ 
    cout << "val\n"; 
    my_obj temp = forward<T>(a); 
} 

a不是轉發引用,它是一個左值引用。類型T不是參考類型。所以forward<T>(a)的行爲與move(a)相同。轉發參考的特殊情況是模板參數推導爲參考類型,並且使用參考類型轉發產生左值。

你只是想my_obj temp = a;

+4

@pyjg沒有理由感到愚蠢。每個人都必須在某個時候學習。 – Barry

+0

所以正確的修復將是'my_obj temp = a;'在那個函數中? – PYA

+3

@pyjg是的。轉發的目的是保留值類別,但在這裏我們知道我們有一個左值。通常情況下,您只想「轉發」轉發引用 - 而您沒有轉發引用,因此請勿轉發。 (「正確的」轉發將是'轉發(a)',但請不要寫這些)。 – Barry

2

此舉構造函數,因爲你正在使用std::forward不轉發引用調用(千萬不要說請)。基本上,此行是罪魁禍首:

my_obj temp = forward<T>(a); 

這裏,Tmy_obj。請記住,std::forward只是一個榮耀的演員。在你的情況下,它相當於:

my_obj temp = static_cast<my_obj&&>(a); 

所以,你是鑄造a到右值引用和右值有移動的語義,所以你看到的移動構造函數被調用。你基本上得到了std::move的行爲。