2017-04-06 64 views
1

我對C++還很陌生,所以請耐心等待。String沒有做什麼? C++ 11

我想了解更多關於std :: move是如何工作的,我看到一個例子,他們使用std :: move將字符串移動到不同的函數,然後使用std :: cout顯示沒有字符串保留。我覺得很酷,讓我們來看看,如果我可以讓我自己的類,做同樣的:

#include <iostream> 
#include <string> 

class integer 
{ 
private: 
    int *m_i; 
public: 
    integer(int i=0) : m_i(new int{i}) 
    { 
     std::cout << "Calling Constructor\n"; 
    } 

    ~integer() 
    { 
     if(m_i != nullptr) { 
      std::cout << "Deleting integer\n"; 
      delete m_i; 
      m_i = nullptr; 
     } 
    } 

    integer(integer&& i) : m_i(nullptr) // move constructor 
    { 
     std::cout << "Move Constructor\n"; 
     m_i = i.m_i; 
     i.m_i = nullptr; 
    } 
    integer(const integer& i) : m_i(new int) { // copy constructor 
     std::cout << "Copy Constructor\n"; 
     *m_i = *(i.m_i); 
    } 
//* 
    integer& operator=(integer&& i) { // move assignment 
     std::cout << "Move Assignment\n"; 
     if(&i != this) { 
      delete m_i; 
      m_i = i.m_i; 
      i.m_i = nullptr; 
     } 
     return *this; 
    } 
    integer& operator=(const integer &i) { // copy assignment 
     std::cout << "Copy Assignment\n"; 
     if(&i != this) { 
      m_i = new int; 
      *m_i = *(i.m_i); 
     } 
     return *this; 
    } 
    int& operator*() const { return *m_i; } 
    int* operator->() const { return m_i; } 

    bool empty() const noexcept { 
     if(m_i == nullptr) return true; 
     return false; 
    } 

    friend std::ostream& operator<<(std::ostream &out, const integer i) { 
     if(i.empty()) { 
      std::cout << "During overload, i is empty\n"; 
      return out; 
     } 
    out << *(i.m_i); 
    return out; 
    } 
}; 

void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; } 
void g(std::string s) { std::cout << "The g value is " << s << '\n'; } 

int main() 
{ 
    std::string s("Hello"); 

    std::cout << "Now for string\n"; 
    g(std::move(s)); 
    if(s.empty()) std::cout << "s is empty\n"; 
    g(s); 
    std::cout << "\nNow for integer\n"; 
    integer i = 77; 
    if(!i.empty()) std::cout << "i is " << i << '\n'; 
    else std::cout << "i is empty\n"; 
    g(i); 
    std::cout << "Move it\n"; 
    g(std::move(i)); // rvalue ref called 
    if(!i.empty()) std::cout << "i is " << i << '\n'; 
    else std::cout << "i is empty\n"; 
    g(i); 

    return 0; 
} 

這是我的輸出:

Now for string 
The g value is Hello 
s is empty 
The g value is 

Now for integer 
Calling Constructor 
Copy Constructor 
i is 77 
Deleting integer 
Copy Constructor 
G-wiz - Copy Constructor 
The g value is 77 
Deleting integer 
Deleting integer 
Move it 
Move Constructor 
G-wiz - Copy Constructor 
The g value is 77 
Deleting integer 
Deleting integer 
i is empty 
Copy Constructor 

Process returned 255 (0xFF) execution time : 7.633 s 
Press any key to continue. 

正如你所看到的,當它進入克崩潰第二次,甚至從未獲得運營商< <()的功能。它是如何空std ::字符串s可以傳遞給g我的空整數我崩潰程序?

編輯:修正新的int與新的int []錯誤。謝謝你。

+0

手動移動構造函數通常使用'std :: move'移動成員。 – Peter

+0

感謝您的幫助,解決了問題。如果我理解的是,在移動構造函數(和賦值運算符)中,我將i.m_i視爲左值而不是右值。是對的嗎? – davidbear

回答

1

您的「空整數」會因程序包含空指針而導致程序崩潰。當您在作業的右側使用它時,您正試圖對其進行解引用。

空字符串是一個正常的可用字符串。 std::string代碼中沒有未經檢查的空指針取消引用。

你必須確保你的對象的空狀態是一個可用的狀態。從定義默認構造函數開始。這對你的班級有意義嗎?如果不是,那麼移動語義可能也不會。如果是,則移動構造函數中的移動對象應該最終處於與默認構造對象相同的狀態。移動分配可以充當交換操作,所以右側可能會空或不空。

如果你不想爲你的類定義一個可用的空狀態,並且仍然希望移動語義,那麼你就不能在它被移動後使用一個對象。你仍然需要確保一個空物體是可破壞的。

+0

這個練習的要點不實用,但要學習std :: move如何工作。如何讓一個空物體破壞? – davidbear

+1

析構函數不應該崩潰或有其他不良行爲。它取決於析構函數的作用,但基本上如果有一個指針想要「刪除」,指針必須指向一個可以被刪除的對象,或者是一個「nullptr」。你們班上已經有這個了。注意另一個bug,有時候你會調用'new int',有時候會調用'new int [1]'。這是非法的。 –

+0

我修正了「new int/new int [1]」的問題(謝謝,見上)。我已經確定在調用std :: cout之前程序崩潰了,所以用空的整數調用g的行爲與用空std :: string調用g不同。我仍然錯過了一些東西。對不起,如此密集。 – davidbear

相關問題